Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1114,22 +1114,29 @@ void Preprocessor::dump(std::ostream &out) const
std::size_t Preprocessor::calculateHash(const std::string &toolinfo) const
{
std::string hashData = toolinfo;
for (const simplecpp::Token *tok = mTokens.cfront(); tok; tok = tok->next) {
if (!tok->comment) {
hashData += tok->str();
hashData += static_cast<char>(tok->location.line);
hashData += static_cast<char>(tok->location.col);
}
}
for (const auto &filedata : mFileCache) {
for (const simplecpp::Token *tok = filedata->tokens.cfront(); tok; tok = tok->next) {
const auto addTokens = [&hashData](const simplecpp::TokenList &tokens) {
for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) {
if (!tok->comment) {
hashData += tok->str();
hashData += static_cast<char>(tok->location.line);
hashData += static_cast<char>(tok->location.col);
}
}
}
};
addTokens(mTokens);

// Hash the included files in a fixed order, the order they are loaded in differs between runs
std::vector<const simplecpp::FileData *> fileData;
fileData.reserve(mFileCache.size());
std::transform(mFileCache.cbegin(), mFileCache.cend(), std::back_inserter(fileData), [](const std::unique_ptr<simplecpp::FileData> &data) {
return data.get();
});
std::sort(fileData.begin(), fileData.end(), [](const simplecpp::FileData *a, const simplecpp::FileData *b) {
return a->filename < b->filename;
});
for (const simplecpp::FileData *data : fileData)
addTokens(data->tokens);

return (std::hash<std::string>{})(hashData);
}

Expand Down
41 changes: 41 additions & 0 deletions test/cli/other_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4575,6 +4575,47 @@ def run_and_assert_cppcheck(stdout_exp):
# - internalError


def test_analyzerinfo_include_order(tmp_path): # #15132
with open(tmp_path / 'z.h', 'wt') as f:
f.write('int z;\n')
with open(tmp_path / 'a.h', 'wt') as f:
f.write('int a;\n')
test_file = tmp_path / 'test.c'
with open(test_file, 'wt') as f:
f.write(
"""#include "z.h"
#include "a.h"
int f(void) { return a + z; }
""")

build_dir = tmp_path / 'b1'
os.makedirs(build_dir)

args = [
'-q',
'--debug-analyzerinfo',
'--cppcheck-build-dir={}'.format(build_dir),
str(test_file)
]

test_file_s = str(test_file).replace('\\', '/')
test_a1_file_s = str(build_dir / 'test.a1').replace('\\', '/')

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0, stdout
assert stdout.splitlines() == [
"no cached result '{}' for '{}' found".format(test_a1_file_s, test_file_s)
]
assert stderr.splitlines() == []

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0, stdout
assert stdout.splitlines() == [
"skipping analysis - loaded 0 cached finding(s) from '{}' for '{}'".format(test_a1_file_s, test_file_s)
]
assert stderr.splitlines() == []


def test_ctu_function_call_path_slash(tmp_path): # #14591
test_file = tmp_path / 'test.cpp'
with open(test_file, "w") as f:
Expand Down
20 changes: 20 additions & 0 deletions test/testpreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ class TestPreprocessor : public TestFixture {
TEST_CASE(limitsDefines);

TEST_CASE(hashCalculation);
TEST_CASE(hashCalculationIncludeOrder);

TEST_CASE(standard);

Expand Down Expand Up @@ -3182,6 +3183,25 @@ class TestPreprocessor : public TestFixture {
ASSERT(getHash(code2) != getHash(code3));
}

void hashCalculationIncludeOrder() {
// #15132 - the load order of the includes must not change the hash
const ScopedFile headerA("hash_a.h", "int a;\n");
const ScopedFile headerZ("hash_z.h", "int z;\n");
const char code[] = "#include \"hash_z.h\"\n"
"#include \"hash_a.h\"\n";

const auto getHashLoadOrder = [&](const std::vector<std::string> &loadOrder) {
std::vector<std::string> files;
simplecpp::TokenList tokens(code, files, "test.c");
Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C);
for (const std::string &header : loadOrder)
ASSERT(preprocessor.loadFile(files, header));
return preprocessor.calculateHash("");
};

ASSERT_EQUALS(getHashLoadOrder({"hash_z.h", "hash_a.h"}), getHashLoadOrder({"hash_a.h", "hash_z.h"}));
}

void standard() {

const char code[] = "int a;\n";
Expand Down
Loading