Skip to content
Draft

14974 #8801

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
15 changes: 11 additions & 4 deletions externals/simplecpp/simplecpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3154,13 +3154,10 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::tryload(FileDat
mImpl->mIdMap.emplace(fileId, data);
mData.emplace_back(data);

if (mLoadCallback)
mLoadCallback(*data);

return {data, true};
}

std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::get(const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader, std::vector<std::string> &filenames, simplecpp::OutputList *outputList)
std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::get_private(const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader, std::vector<std::string> &filenames, simplecpp::OutputList *outputList)
{
if (isAbsolutePath(header)) {
auto ins = mNameMap.emplace(simplecpp::simplifyPath(header), nullptr);
Expand Down Expand Up @@ -3206,6 +3203,16 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::get(const std::
return {nullptr, false};
}

std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::get(const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader, std::vector<std::string> &filenames, simplecpp::OutputList *outputList)
{
auto ret = get_private(sourcefile, header, dui, systemheader, filenames, outputList);

if (mLoadCallback && ret.first)
mLoadCallback(*ret.first, ret.second);

return ret;
}

void simplecpp::FileDataCache::clear()
{
mImpl->clear();
Expand Down
3 changes: 2 additions & 1 deletion externals/simplecpp/simplecpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ namespace simplecpp {
return mData.cend();
}

using load_callback_type = std::function<void (FileData &)>;
using load_callback_type = std::function<void (FileData &, bool)>;

void set_load_callback(load_callback_type cb) {
mLoadCallback = std::move(cb);
Expand All @@ -512,6 +512,7 @@ namespace simplecpp {
using name_map_type = std::unordered_map<std::string, FileData *>;

std::pair<FileData *, bool> tryload(name_map_type::iterator &name_it, const DUI &dui, std::vector<std::string> &filenames, OutputList *outputList);
std::pair<FileData *, bool> get_private(const std::string &sourcefile, const std::string &header, const DUI &dui, bool systemheader, std::vector<std::string> &filenames, OutputList *outputList);

container_type mData;
name_map_type mNameMap;
Expand Down
56 changes: 56 additions & 0 deletions lib/analyzerinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,61 @@ void AnalyzerInformation::writeFilesTxt(const std::string &buildDir, const std::
fout << getFilesTxt(sourcefiles, fileSettings);
}

void AnalyzerInformation::writeIncludes(const std::set<std::string> &files)
{
if (mOutputStream.is_open()) {
mOutputStream << " <includes>\n";
for (const std::string &file : files) {
mOutputStream << " <filename>" << file << "</filename>\n";
}
mOutputStream << " </includes>\n";
}
}

std::set<std::string> AnalyzerInformation::getIncludes(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId)
{
if (mOutputStream.is_open())
throw std::runtime_error("analyzer information file is already open");

std::set<std::string> files;

if (buildDir.empty() || sourcefile.empty())
return files;

const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir, sourcefile, cfg, fsFileId);

tinyxml2::XMLDocument analyzerInfoDoc;
if (analyzerInfoDoc.LoadFile(analyzerInfoFile.c_str()) != tinyxml2::XML_SUCCESS)
return files;

const tinyxml2::XMLElement *const rootNode = analyzerInfoDoc.FirstChildElement();
if (rootNode == nullptr)
return files;

if (strcmp(rootNode->Name(), "analyzerinfo") != 0)
return files;

const tinyxml2::XMLElement *cachedfilesNode = nullptr;
for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (strcmp(e->Name(), "includes") == 0) {
cachedfilesNode = e;
break;
}
}

if (cachedfilesNode == nullptr)
return files;

for (const tinyxml2::XMLElement *e = cachedfilesNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
if (strcmp(e->Name(), "filename") != 0)
continue;

files.insert(e->GetText());
}

return files;
}

std::string AnalyzerInformation::getFilesTxt(const std::list<std::string> &sourcefiles, const std::list<FileSettings> &fileSettings) {
std::ostringstream ret;

Expand Down Expand Up @@ -172,6 +227,7 @@ bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::st
tinyxml2::XMLDocument analyzerInfoDoc;
const tinyxml2::XMLError xmlError = analyzerInfoDoc.LoadFile(analyzerInfoFile.c_str());
if (xmlError == tinyxml2::XML_SUCCESS) {

const std::string err = skipAnalysis(analyzerInfoDoc, hash, errors);
if (err.empty()) {
if (debug)
Expand Down
3 changes: 3 additions & 0 deletions lib/analyzerinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <fstream>
#include <functional>
#include <list>
#include <set>
#include <string>

class ErrorMessage;
Expand Down Expand Up @@ -67,6 +68,8 @@ class CPPCHECKLIB AnalyzerInformation {
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);
void reportErr(const ErrorMessage &msg);
void setFileInfo(const std::string &check, const std::string &fileInfo);
void writeIncludes(const std::set<std::string> &files);
std::set<std::string> getIncludes(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);

void reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);
Expand Down
76 changes: 46 additions & 30 deletions lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1022,25 +1022,6 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
preprocessor.inlineSuppressions(mSuppressions.nomsg);
preprocessor.removeComments();

if (!mSettings.buildDir.empty()) {
analyzerInformation.reset(new AnalyzerInformation);
mLogger->setAnalyzerInfo(analyzerInformation.get());
}

if (analyzerInformation) {
// Calculate hash so it can be compared with old hash / future hashes
const std::size_t hash = calculateHash(preprocessor, file.spath());
std::list<ErrorMessage> errors;
if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, file.fsFileId(), hash, errors, mSettings.debugainfo)) {
while (!errors.empty()) {
mErrorLogger.reportErr(errors.front());
errors.pop_front();
}
mLogger->setAnalyzerInfo(nullptr);
return mLogger->exitcode(); // known results => no need to reanalyze file
}
}

// Get directives
std::list<Directive> directives;
preprocessor.createDirectives(directives);
Expand All @@ -1058,26 +1039,57 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
std::inserter(configDefines, configDefines.end()),
getDefineName);

preprocessor.setLoadCallback([&](simplecpp::FileData &data) {
// Do preprocessing on included file
mLogger->addRemarkComments(preprocessor.getRemarkComments(data.tokens));
preprocessor.inlineSuppressions(data.tokens, mSuppressions.nomsg);
Preprocessor::removeComments(data.tokens);
Preprocessor::createDirectives(data.tokens, directives);
Preprocessor::simplifyPragmaAsm(data.tokens);
// Discover new configurations from included file
if (configurations.size() < maxConfigs)
preprocessor.getConfigs(data.filename, data.tokens, configDefines, configurations);
// Keep track of all included files
std::set<std::string> includedFiles;

preprocessor.setLoadCallback([&](simplecpp::FileData &data, bool loaded) {
includedFiles.insert(data.filename);
if (loaded) {
// Do preprocessing on included file
mLogger->addRemarkComments(preprocessor.getRemarkComments(data.tokens));
preprocessor.inlineSuppressions(data.tokens, mSuppressions.nomsg);
Preprocessor::removeComments(data.tokens);
Preprocessor::createDirectives(data.tokens, directives);
Preprocessor::simplifyPragmaAsm(data.tokens);
// Discover new configurations from included file
if (configurations.size() < maxConfigs)
preprocessor.getConfigs(data.filename, data.tokens, configDefines, configurations);
}
});

preprocessor.setPlatformInfo();

if (!mSettings.buildDir.empty()) {
analyzerInformation.reset(new AnalyzerInformation);
mLogger->setAnalyzerInfo(analyzerInformation.get());
}

if (analyzerInformation) {
// Load all included files to get correct hashes and suppressions
for (const std::string &filename : analyzerInformation->getIncludes(mSettings.buildDir, file.spath(), cfgname, file.fsFileId()))
preprocessor.loadFile(files, filename);
// Calculate hash so it can be compared with old hash / future hashes
const std::size_t hash = calculateHash(preprocessor, file.spath());
std::list<ErrorMessage> errors;
if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, file.fsFileId(), hash, errors, mSettings.debugainfo)) {
while (!errors.empty()) {
mErrorLogger.reportErr(errors.front());
errors.pop_front();
}
mLogger->setAnalyzerInfo(nullptr);
return mLogger->exitcode(); // known results => no need to reanalyze file
}
// Clear included file list; we don't want to keep includes that have been removed from the source
// Any includes that are still present will be readded
includedFiles.clear();
}

// Get configurations..
if (maxConfigs > 1) {
Timer::run("Preprocessor::getConfigs", mTimerResults, [&]() {
configurations = { "" };
preprocessor.getConfigs(configDefines, configurations);
preprocessor.loadFiles(files);
preprocessor.loadAllIncludes(files);
});
} else {
configurations = { mSettings.userDefines };
Expand Down Expand Up @@ -1300,6 +1312,10 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
mLogger->setPlistFilenames(std::move(files));
}

if (analyzerInformation) {
analyzerInformation->writeIncludes(includedFiles);
}

executeAddons(dumpFile, file);
} catch (const TerminateException &) {
// Analysis is terminated
Expand Down
9 changes: 8 additions & 1 deletion lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ const simplecpp::Output* Preprocessor::handleErrors(const simplecpp::OutputList&
return reportOutput(outputList, showerror);
}

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

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

simplecpp::FileData *Preprocessor::loadFile(std::vector<std::string> &files, const std::string &file)
{
const simplecpp::DUI dui = createDUI(mSettings, "", mLang);

return mFileCache.get("", file, dui, false, files, nullptr).first;
}

void Preprocessor::removeComments()
{
removeComments(mTokens);
Expand Down
8 changes: 5 additions & 3 deletions lib/preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {

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

bool loadFiles(std::vector<std::string> &files);
bool loadAllIncludes(std::vector<std::string> &files);

simplecpp::FileData *loadFile(std::vector<std::string> &files, const std::string &file);

void removeComments();

Expand Down Expand Up @@ -163,6 +165,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {
mFileCache.set_load_callback(std::move(cb));
}

simplecpp::FileDataCache mFileCache;

private:

/**
Expand All @@ -182,8 +186,6 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor {
const Settings& mSettings;
ErrorLogger &mErrorLogger;

simplecpp::FileDataCache mFileCache;

/** filename for cpp/c file - useful when reporting errors */
std::string mFile0; // TODO: this is never set
Standards::Language mLang{Standards::Language::None};
Expand Down
2 changes: 1 addition & 1 deletion test/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ void SimpleTokenizer2::preprocess(const char* code, std::size_t size, std::vecto
simplecpp::TokenList tokens1({code, size}, files, file0, &outputList);

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

Expand Down
2 changes: 1 addition & 1 deletion test/testcppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ class TestCppcheck : public TestFixture {
simplecpp::TokenList tokens(code, files, "m1.c");

Preprocessor preprocessor(tokens, settings, errorLogger, Standards::Language::C);
ASSERT(preprocessor.loadFiles(files));
ASSERT(preprocessor.loadAllIncludes(files));

AddonInfo premiumaddon;
premiumaddon.name = "premiumaddon.json";
Expand Down
10 changes: 5 additions & 5 deletions test/testpreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class TestPreprocessor : public TestFixture {
std::vector<std::string> files;
simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", &outputList);
Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false));
ASSERT_LOC(p.loadFiles(files), file, line);
ASSERT_LOC(p.loadAllIncludes(files), file, line);
simplecpp::TokenList tokens2 = p.preprocess("", files, outputList);
(void)p.reportOutput(outputList, true);
return tokens2.stringify();
Expand Down Expand Up @@ -410,13 +410,13 @@ class TestPreprocessor : public TestFixture {
settings.library.defines().end(),
std::inserter(configDefines, configDefines.end()),
getDefineName);
preprocessor.setLoadCallback([&](simplecpp::FileData &data) {
preprocessor.setLoadCallback([&](simplecpp::FileData &data, bool) {
Preprocessor::removeComments(data.tokens);
preprocessor.getConfigs(data.filename, data.tokens, configDefines, configs);
});
preprocessor.removeComments();
preprocessor.getConfigs(configDefines, configs);
ASSERT(preprocessor.loadFiles(files));
ASSERT(preprocessor.loadAllIncludes(files));
ASSERT(!preprocessor.reportOutput(outputList, true));
std::string ret;
for (const std::string & config : configs)
Expand All @@ -429,11 +429,11 @@ class TestPreprocessor : public TestFixture {
std::vector<std::string> files;
simplecpp::TokenList tokens(code,files,"test.c");
Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C);
preprocessor.setLoadCallback([](simplecpp::FileData &data) {
preprocessor.setLoadCallback([](simplecpp::FileData &data, bool) {
Preprocessor::removeComments(data.tokens);
});
preprocessor.removeComments();
ASSERT(preprocessor.loadFiles(files));
ASSERT(preprocessor.loadAllIncludes(files));
return preprocessor.calculateHash("");
}

Expand Down
4 changes: 2 additions & 2 deletions test/testtokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,11 +608,11 @@ class TestTokenizer : public TestFixture {
simplecpp::TokenList tokens1(code, files, filename, &outputList);
Preprocessor preprocessor(tokens1, settings, *this, Path::identify(tokens1.getFiles()[0], false));
std::list<Directive> directives;
preprocessor.setLoadCallback([&](const simplecpp::FileData &data) {
preprocessor.setLoadCallback([&](const simplecpp::FileData &data, bool) {
Preprocessor::createDirectives(data.tokens, directives);
});
preprocessor.createDirectives(directives);
ASSERT(preprocessor.loadFiles(files));
ASSERT(preprocessor.loadAllIncludes(files));
(void)preprocessor.reportOutput(outputList, true);

TokenList tokenlist{settings, Path::identify(filename, false)};
Expand Down
Loading