Skip to content

Commit e06f755

Browse files
committed
Fix 14974
1 parent c6109ba commit e06f755

9 files changed

Lines changed: 109 additions & 28 deletions

lib/analyzerinfo.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,61 @@ void AnalyzerInformation::writeFilesTxt(const std::string &buildDir, const std::
5858
fout << getFilesTxt(sourcefiles, fileSettings);
5959
}
6060

61+
void AnalyzerInformation::writeIncludes(const std::set<std::string> &files)
62+
{
63+
if (mOutputStream.is_open()) {
64+
mOutputStream << " <includes>\n";
65+
for (const std::string &file : files) {
66+
mOutputStream << " <filename>" << file << "</filename>\n";
67+
}
68+
mOutputStream << " </includes>\n";
69+
}
70+
}
71+
72+
std::set<std::string> AnalyzerInformation::getIncludes(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId)
73+
{
74+
if (mOutputStream.is_open())
75+
throw std::runtime_error("analyzer information file is already open");
76+
77+
std::set<std::string> files;
78+
79+
if (buildDir.empty() || sourcefile.empty())
80+
return files;
81+
82+
const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir, sourcefile, cfg, fsFileId);
83+
84+
tinyxml2::XMLDocument analyzerInfoDoc;
85+
if (analyzerInfoDoc.LoadFile(analyzerInfoFile.c_str()) != tinyxml2::XML_SUCCESS)
86+
return files;
87+
88+
const tinyxml2::XMLElement *const rootNode = analyzerInfoDoc.FirstChildElement();
89+
if (rootNode == nullptr)
90+
return files;
91+
92+
if (strcmp(rootNode->Name(), "analyzerinfo") != 0)
93+
return files;
94+
95+
const tinyxml2::XMLElement *cachedfilesNode = nullptr;
96+
for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
97+
if (strcmp(e->Name(), "includes") == 0) {
98+
cachedfilesNode = e;
99+
break;
100+
}
101+
}
102+
103+
if (cachedfilesNode == nullptr)
104+
return files;
105+
106+
for (const tinyxml2::XMLElement *e = cachedfilesNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
107+
if (strcmp(e->Name(), "filename") != 0)
108+
continue;
109+
110+
files.insert(e->GetText());
111+
}
112+
113+
return files;
114+
}
115+
61116
std::string AnalyzerInformation::getFilesTxt(const std::list<std::string> &sourcefiles, const std::list<FileSettings> &fileSettings) {
62117
std::ostringstream ret;
63118

lib/analyzerinfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <fstream>
2828
#include <functional>
2929
#include <list>
30+
#include <set>
3031
#include <string>
3132

3233
class ErrorMessage;
@@ -67,6 +68,8 @@ class CPPCHECKLIB AnalyzerInformation {
6768
bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId, std::size_t hash, std::list<ErrorMessage> &errors, bool debug = false);
6869
void reportErr(const ErrorMessage &msg);
6970
void setFileInfo(const std::string &check, const std::string &fileInfo);
71+
void writeIncludes(const std::set<std::string> &files);
72+
std::set<std::string> getIncludes(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);
7073
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);
7174

7275
void reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);

lib/cppcheck.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,25 +1026,6 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
10261026
preprocessor.inlineSuppressions(mSuppressions.nomsg);
10271027
preprocessor.removeComments();
10281028

1029-
if (!mSettings.buildDir.empty()) {
1030-
analyzerInformation.reset(new AnalyzerInformation);
1031-
mLogger->setAnalyzerInfo(analyzerInformation.get());
1032-
}
1033-
1034-
if (analyzerInformation) {
1035-
// Calculate hash so it can be compared with old hash / future hashes
1036-
const std::size_t hash = calculateHash(preprocessor, file.spath());
1037-
std::list<ErrorMessage> errors;
1038-
if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, file.fsFileId(), hash, errors, mSettings.debugainfo)) {
1039-
while (!errors.empty()) {
1040-
mErrorLogger.reportErr(errors.front());
1041-
errors.pop_front();
1042-
}
1043-
mLogger->setAnalyzerInfo(nullptr);
1044-
return mLogger->exitcode(); // known results => no need to reanalyze file
1045-
}
1046-
}
1047-
10481029
// Get directives
10491030
std::list<Directive> directives;
10501031
preprocessor.createDirectives(directives);
@@ -1062,7 +1043,11 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
10621043
std::inserter(configDefines, configDefines.end()),
10631044
getDefineName);
10641045

1046+
// Keep track of all included files
1047+
std::set<std::string> includedFiles;
1048+
10651049
preprocessor.setLoadCallback([&](simplecpp::FileData &data, bool loaded) {
1050+
includedFiles.insert(data.filename);
10661051
if (loaded) {
10671052
// Do preprocessing on included file
10681053
mLogger->addRemarkComments(preprocessor.getRemarkComments(data.tokens));
@@ -1078,12 +1063,37 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
10781063

10791064
preprocessor.setPlatformInfo();
10801065

1066+
if (!mSettings.buildDir.empty()) {
1067+
analyzerInformation.reset(new AnalyzerInformation);
1068+
mLogger->setAnalyzerInfo(analyzerInformation.get());
1069+
}
1070+
1071+
if (analyzerInformation) {
1072+
// Load all included files to get correct hashes and suppressions
1073+
for (const std::string &filename : analyzerInformation->getIncludes(mSettings.buildDir, file.spath(), cfgname, file.fsFileId()))
1074+
preprocessor.loadFile(files, filename);
1075+
// Calculate hash so it can be compared with old hash / future hashes
1076+
const std::size_t hash = calculateHash(preprocessor, file.spath());
1077+
std::list<ErrorMessage> errors;
1078+
if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, file.fsFileId(), hash, errors, mSettings.debugainfo)) {
1079+
while (!errors.empty()) {
1080+
mErrorLogger.reportErr(errors.front());
1081+
errors.pop_front();
1082+
}
1083+
mLogger->setAnalyzerInfo(nullptr);
1084+
return mLogger->exitcode(); // known results => no need to reanalyze file
1085+
}
1086+
// Clear included file list; we don't want to keep includes that have been removed from the source
1087+
// Any includes that are still present will be readded
1088+
includedFiles.clear();
1089+
}
1090+
10811091
// Get configurations..
10821092
if (maxConfigs > 1) {
10831093
Timer::run("Preprocessor::getConfigs", mTimerResults, [&]() {
10841094
configurations = { "" };
10851095
preprocessor.getConfigs(configDefines, configurations);
1086-
preprocessor.loadFiles(files);
1096+
preprocessor.loadAllIncludes(files);
10871097
});
10881098
} else {
10891099
configurations = { mSettings.userDefines };
@@ -1306,6 +1316,10 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
13061316
mLogger->setPlistFilenames(std::move(files));
13071317
}
13081318

1319+
if (analyzerInformation) {
1320+
analyzerInformation->writeIncludes(includedFiles);
1321+
}
1322+
13091323
executeAddons(dumpFile, file);
13101324
} catch (const TerminateException &) {
13111325
// Analysis is terminated

lib/preprocessor.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ const simplecpp::Output* Preprocessor::handleErrors(const simplecpp::OutputList&
833833
return reportOutput(outputList, showerror);
834834
}
835835

836-
bool Preprocessor::loadFiles(std::vector<std::string> &files)
836+
bool Preprocessor::loadAllIncludes(std::vector<std::string> &files)
837837
{
838838
const simplecpp::DUI dui = createDUI(mSettings, "", mLang);
839839

@@ -842,6 +842,13 @@ bool Preprocessor::loadFiles(std::vector<std::string> &files)
842842
return !handleErrors(outputList);
843843
}
844844

845+
simplecpp::FileData *Preprocessor::loadFile(std::vector<std::string> &files, const std::string &file)
846+
{
847+
const simplecpp::DUI dui = createDUI(mSettings, "", mLang);
848+
849+
return mFileCache.get("", file, dui, false, files, nullptr).first;
850+
}
851+
845852
void Preprocessor::removeComments()
846853
{
847854
removeComments(mTokens);

lib/preprocessor.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {
122122

123123
std::vector<RemarkComment> getRemarkComments(const simplecpp::TokenList &tokens) const;
124124

125-
bool loadFiles(std::vector<std::string> &files);
125+
bool loadAllIncludes(std::vector<std::string> &files);
126+
127+
simplecpp::FileData *loadFile(std::vector<std::string> &files, const std::string &file);
126128

127129
void removeComments();
128130

test/helpers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void SimpleTokenizer2::preprocess(const char* code, std::size_t size, std::vecto
121121
simplecpp::TokenList tokens1({code, size}, files, file0, dui, &outputList);
122122

123123
Preprocessor preprocessor(tokens1, tokenizer.getSettings(), errorlogger, Path::identify(tokens1.getFiles()[0], false));
124-
(void)preprocessor.loadFiles(files); // TODO: check result
124+
(void)preprocessor.loadAllIncludes(files); // TODO: check result
125125
simplecpp::TokenList tokens2 = preprocessor.preprocess("", files, outputList);
126126
(void)preprocessor.reportOutput(outputList, true);
127127

test/testcppcheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ class TestCppcheck : public TestFixture {
573573
simplecpp::TokenList tokens(code, files, "m1.c");
574574

575575
Preprocessor preprocessor(tokens, settings, errorLogger, Standards::Language::C);
576-
ASSERT(preprocessor.loadFiles(files));
576+
ASSERT(preprocessor.loadAllIncludes(files));
577577

578578
AddonInfo premiumaddon;
579579
premiumaddon.name = "premiumaddon.json";

test/testpreprocessor.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class TestPreprocessor : public TestFixture {
5959
std::vector<std::string> files;
6060
simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", {}, &outputList);
6161
Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false));
62-
ASSERT_LOC(p.loadFiles(files), file, line);
62+
ASSERT_LOC(p.loadAllIncludes(files), file, line);
6363
simplecpp::TokenList tokens2 = p.preprocess("", files, outputList);
6464
(void)p.reportOutput(outputList, true);
6565
return tokens2.stringify();
@@ -420,7 +420,7 @@ class TestPreprocessor : public TestFixture {
420420
});
421421
preprocessor.removeComments();
422422
preprocessor.getConfigs(configDefines, configs);
423-
ASSERT(preprocessor.loadFiles(files));
423+
ASSERT(preprocessor.loadAllIncludes(files));
424424
ASSERT(!preprocessor.reportOutput(outputList, true));
425425
std::string ret;
426426
for (const std::string & config : configs)
@@ -439,7 +439,7 @@ class TestPreprocessor : public TestFixture {
439439
}
440440
});
441441
preprocessor.removeComments();
442-
ASSERT(preprocessor.loadFiles(files));
442+
ASSERT(preprocessor.loadAllIncludes(files));
443443
return preprocessor.calculateHash("");
444444
}
445445

test/testtokenize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ class TestTokenizer : public TestFixture {
615615
}
616616
});
617617
preprocessor.createDirectives(directives);
618-
ASSERT(preprocessor.loadFiles(files));
618+
ASSERT(preprocessor.loadAllIncludes(files));
619619
(void)preprocessor.reportOutput(outputList, true);
620620

621621
TokenList tokenlist{settings, Path::identify(filename, false)};

0 commit comments

Comments
 (0)