Skip to content

Commit 903cf7f

Browse files
Tal500Tal Hadad
authored andcommitted
fix: parent relative paths, and rework on the whole path extraction mechanics
Include also another integration test function to check header in parent dir usage (was failing before)
1 parent 2bbb496 commit 903cf7f

2 files changed

Lines changed: 102 additions & 36 deletions

File tree

integration_test.py

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,16 @@ def __test_relative_header_create_source(dir, include1, include2, is_include1_sy
3535

3636
@pytest.mark.parametrize("with_pragma_once", (False, True))
3737
@pytest.mark.parametrize("is_sys", (False, True))
38-
def test_relative_header_1(tmpdir, with_pragma_once, is_sys):
38+
def test_relative_header_1(record_property, tmpdir, with_pragma_once, is_sys):
3939
_, double_include_error = __test_relative_header_create_header(tmpdir, with_pragma_once=with_pragma_once)
4040

4141
test_file = __test_relative_header_create_source(tmpdir, "test.h", "test.h", is_include1_sys=is_sys, is_include2_sys=is_sys)
4242

4343
args = ([format_include_path_arg(tmpdir)] if is_sys else []) + [test_file]
4444

45-
_, _, stderr = simplecpp(args, cwd=tmpdir)
45+
_, stdout, stderr = simplecpp(args, cwd=tmpdir)
46+
record_property("stdout", stdout)
47+
record_property("stderr", stderr)
4648

4749
if with_pragma_once:
4850
assert stderr == ''
@@ -51,14 +53,16 @@ def test_relative_header_1(tmpdir, with_pragma_once, is_sys):
5153

5254
@pytest.mark.parametrize("inv", (False, True))
5355
@pytest.mark.parametrize("source_relative", (False, True))
54-
def test_relative_header_2(tmpdir, inv, source_relative):
56+
def test_relative_header_2(record_property, tmpdir, inv, source_relative):
5557
header_file, _ = __test_relative_header_create_header(tmpdir)
5658

5759
test_file = __test_relative_header_create_source(tmpdir, "test.h", header_file, inv=inv)
5860

5961
args = ["test.c" if source_relative else test_file]
6062

6163
_, stdout, stderr = simplecpp(args, cwd=tmpdir)
64+
record_property("stdout", stdout)
65+
record_property("stderr", stderr)
6266
assert stderr == ''
6367
if source_relative and not inv:
6468
assert '#line 8 "test.h"' in stdout
@@ -68,7 +72,7 @@ def test_relative_header_2(tmpdir, inv, source_relative):
6872
@pytest.mark.parametrize("is_sys", (False, True))
6973
@pytest.mark.parametrize("inv", (False, True))
7074
@pytest.mark.parametrize("source_relative", (False, True))
71-
def test_relative_header_3(tmpdir, is_sys, inv, source_relative):
75+
def test_relative_header_3(record_property, tmpdir, is_sys, inv, source_relative):
7276
test_subdir = os.path.join(tmpdir, "test_subdir")
7377
os.mkdir(test_subdir)
7478
header_file, _ = __test_relative_header_create_header(test_subdir)
@@ -78,6 +82,8 @@ def test_relative_header_3(tmpdir, is_sys, inv, source_relative):
7882
args = ["test.c" if source_relative else test_file]
7983

8084
_, stdout, stderr = simplecpp(args, cwd=tmpdir)
85+
record_property("stdout", stdout)
86+
record_property("stderr", stderr)
8187

8288
if is_sys:
8389
assert "missing header: Header not found" in stderr
@@ -91,7 +97,7 @@ def test_relative_header_3(tmpdir, is_sys, inv, source_relative):
9197
@pytest.mark.parametrize("use_short_path", (False, True))
9298
@pytest.mark.parametrize("is_sys", (False, True))
9399
@pytest.mark.parametrize("inv", (False, True))
94-
def test_relative_header_4(tmpdir, use_short_path, is_sys, inv):
100+
def test_relative_header_4(record_property, tmpdir, use_short_path, is_sys, inv):
95101
test_subdir = os.path.join(tmpdir, "test_subdir")
96102
os.mkdir(test_subdir)
97103
header_file, _ = __test_relative_header_create_header(test_subdir)
@@ -102,5 +108,36 @@ def test_relative_header_4(tmpdir, use_short_path, is_sys, inv):
102108

103109
args = [format_include_path_arg(test_subdir), test_file]
104110

105-
_, _, stderr = simplecpp(args, cwd=tmpdir)
111+
_, stdout, stderr = simplecpp(args, cwd=tmpdir)
112+
record_property("stdout", stdout)
113+
record_property("stderr", stderr)
106114
assert stderr == ''
115+
116+
@pytest.mark.parametrize("with_pragma_once", (False, True))
117+
@pytest.mark.parametrize("is_sys", (False, True))
118+
@pytest.mark.parametrize("inv", (False, True))
119+
def test_relative_header_5(record_property, tmpdir, with_pragma_once, is_sys, inv): # test relative paths with ..
120+
## in this test, the subdir role is the opposite then the previous - it contains the test.c file, while the parent tmpdir contains the header file
121+
header_file, double_include_error = __test_relative_header_create_header(tmpdir, with_pragma_once=with_pragma_once)
122+
if is_sys:
123+
header_file_second_path = "test.h"
124+
else:
125+
header_file_second_path = "../test.h"
126+
127+
test_subdir = os.path.join(tmpdir, "test_subdir")
128+
os.mkdir(test_subdir)
129+
test_file = __test_relative_header_create_source(test_subdir, header_file, header_file_second_path, is_include2_sys=is_sys, inv=inv)
130+
131+
args = ([format_include_path_arg(tmpdir)] if is_sys else []) + ["test.c"]
132+
133+
_, stdout, stderr = simplecpp(args, cwd=test_subdir)
134+
record_property("stdout", stdout)
135+
record_property("stderr", stderr)
136+
if with_pragma_once:
137+
assert stderr == ''
138+
if inv:
139+
assert '#line 8 "../test.h"' in stdout
140+
else:
141+
assert f'#line 8 "{pathlib.PurePath(tmpdir).as_posix()}/test.h"' in stdout
142+
else:
143+
assert double_include_error in stderr

simplecpp.cpp

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2719,14 +2719,40 @@ static std::string toAbsolutePath(const std::string& path) {
27192719
return simplecpp::simplifyPath(path);
27202720
}
27212721

2722-
static std::pair<std::string, bool> extractRelativePathFromAbsolute(const std::string& absolutepath) {
2723-
static const std::string prefix = currentDirectory() + "/";
2724-
if (startsWith_(absolutepath, prefix)) {
2725-
const std::size_t size = prefix.size();
2726-
return std::make_pair(absolutepath.substr(size, absolutepath.size() - size), true);
2722+
// templated function for compiler optimization opportunities
2723+
template <bool withTrailingSlash>
2724+
static std::string dirPath(const std::string& path) {
2725+
const std::size_t firstSlash = path.find_last_of("\\/");
2726+
if (firstSlash == std::string::npos) {
2727+
return "";
2728+
} else {
2729+
return path.substr(0, firstSlash + (withTrailingSlash ? 1U : 0U));
27272730
}
2728-
// otherwise
2729-
return std::make_pair("", false);
2731+
}
2732+
2733+
static std::string omitPathTrailingSlash(const std::string& path) {
2734+
if (endsWith(path, "/")) {
2735+
return path.substr(0, path.size() - 1U);
2736+
} else {
2737+
return path;
2738+
}
2739+
}
2740+
2741+
static std::string extractRelativePathFromAbsolute(const std::string& absoluteSimplifiedPath, const std::string& prefixSimplifiedAbsoluteDir = currentDirectory()) {
2742+
const std::string normalizedAbsolutePath = omitPathTrailingSlash(absoluteSimplifiedPath);
2743+
std::string currentPrefix = omitPathTrailingSlash(prefixSimplifiedAbsoluteDir);
2744+
std::string leadingParenting = "";
2745+
while (!startsWith_(normalizedAbsolutePath, currentPrefix)) {
2746+
leadingParenting = "../" + leadingParenting;
2747+
currentPrefix = dirPath<false>(currentPrefix);
2748+
}
2749+
const std::size_t size = currentPrefix.size();
2750+
std::string relativeFromMeetingPath = normalizedAbsolutePath.substr(size, normalizedAbsolutePath.size() - size);
2751+
if (startsWith_(relativeFromMeetingPath.c_str(), "/")) {
2752+
// omit the leading slash
2753+
relativeFromMeetingPath = relativeFromMeetingPath.substr(1, relativeFromMeetingPath.size());
2754+
}
2755+
return leadingParenting + relativeFromMeetingPath;
27302756
}
27312757

27322758
static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const std::string &sourcefile, const std::string &header, bool systemheader);
@@ -3145,19 +3171,25 @@ static std::string openHeader(std::ifstream &f, const std::string &path)
31453171
return "";
31463172
}
31473173

3174+
// templated function for compiler optimization opportunities
3175+
template <bool expandBaseWithAbsolutePath, bool exactRelative>
31483176
static std::string getRelativeFileName(const std::string &baseFile, const std::string &header)
31493177
{
3150-
std::string path;
3151-
if (baseFile.find_first_of("\\/") != std::string::npos)
3152-
path = baseFile.substr(0, baseFile.find_last_of("\\/") + 1U) + header;
3153-
else
3154-
path = header;
3155-
return simplecpp::simplifyPath(path);
3178+
const std::string baseFileNormalized = (expandBaseWithAbsolutePath && !isAbsolutePath(baseFile)) ? (currentDirectory() + "/" + baseFile) : baseFile;
3179+
const std::string path = isAbsolutePath(header) ? header : (dirPath<true>(baseFileNormalized) + header);
3180+
const std::string simplifiedPath = simplecpp::simplifyPath(path);
3181+
if (exactRelative) {
3182+
const std::string absolutePath = expandBaseWithAbsolutePath ? simplifiedPath : toAbsolutePath(simplifiedPath);
3183+
const std::string absoluteBaseFile = expandBaseWithAbsolutePath ? baseFileNormalized : toAbsolutePath(baseFileNormalized);
3184+
return extractRelativePathFromAbsolute(absolutePath, dirPath<true>(absoluteBaseFile));
3185+
} else {
3186+
return simplifiedPath;
3187+
}
31563188
}
31573189

31583190
static std::string openHeaderRelative(std::ifstream &f, const std::string &sourcefile, const std::string &header)
31593191
{
3160-
return openHeader(f, getRelativeFileName(sourcefile, header));
3192+
return openHeader(f, getRelativeFileName<false, false>(sourcefile, header));
31613193
}
31623194

31633195
// returns the simplified header path:
@@ -3174,8 +3206,8 @@ static std::string getIncludePathFileName(const std::string &includePath, const
31743206
std::string basePath = toAbsolutePath(includePath);
31753207
if (!basePath.empty() && basePath[basePath.size()-1U]!='/' && basePath[basePath.size()-1U]!='\\')
31763208
basePath += '/';
3177-
const std::string absolutesimplifiedHeaderPath = basePath + simplifiedHeader;
3178-
return extractRelativePathFromAbsolute(absolutesimplifiedHeaderPath).first;
3209+
const std::string absoluteSimplifiedHeaderPath = basePath + simplifiedHeader;
3210+
return extractRelativePathFromAbsolute(absoluteSimplifiedHeaderPath);
31793211
}
31803212

31813213
static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI &dui, const std::string &header)
@@ -3210,23 +3242,20 @@ static std::string findPathInMapBothRelativeAndAbsolute(const std::map<std::stri
32103242
if (filedata.find(path) != filedata.end()) {// try first to respect the exact match
32113243
return path;
32123244
}
3245+
32133246
// otherwise - try to use the normalize to the correct representation
3247+
std::string alternativePath;
32143248
if (isAbsolutePath(path)) {
3215-
const std::pair<std::string, bool> relativeExtractedResult = extractRelativePathFromAbsolute(path);
3216-
if (relativeExtractedResult.second) {
3217-
const std::string relativePath = relativeExtractedResult.first;
3218-
if (filedata.find(relativePath) != filedata.end()) {
3219-
return relativePath;
3220-
}
3221-
}
3249+
alternativePath = extractRelativePathFromAbsolute(simplecpp::simplifyPath(path));
32223250
} else {
3223-
const std::string absolutePath = toAbsolutePath(path);
3224-
if (filedata.find(absolutePath) != filedata.end()) {
3225-
return absolutePath;
3226-
}
3251+
alternativePath = toAbsolutePath(path);
3252+
}
3253+
3254+
if (filedata.find(alternativePath) != filedata.end()) {
3255+
return alternativePath;
3256+
} else {
3257+
return "";
32273258
}
3228-
// otherwise
3229-
return "";
32303259
}
32313260

32323261
static std::string getFileIdPath(const std::map<std::string, simplecpp::TokenList *> &filedata, const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader)
@@ -3243,7 +3272,7 @@ static std::string getFileIdPath(const std::map<std::string, simplecpp::TokenLis
32433272
}
32443273

32453274
if (!systemheader) {
3246-
const std::string relativeOrAbsoluteFilename = getRelativeFileName(sourcefile, header);// unknown if absolute or relative, but always simplified
3275+
const std::string relativeOrAbsoluteFilename = getRelativeFileName<true, true>(sourcefile, header);// unknown if absolute or relative, but always simplified
32473276
const std::string match = findPathInMapBothRelativeAndAbsolute(filedata, relativeOrAbsoluteFilename);
32483277
if (!match.empty()) {
32493278
return match;

0 commit comments

Comments
 (0)