Skip to content
Draft
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
2 changes: 1 addition & 1 deletion .github/workflows/selfcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ jobs:

- name: Self check (unusedFunction / no test / no gui)
run: |
supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1671 --suppress=unusedFunction:lib/importproject.cpp:1695"
supprs="--suppress=unusedFunction:lib/errorlogger.h:198 --suppress=unusedFunction:lib/importproject.cpp:1671 --suppress=unusedFunction:lib/importproject.cpp:1695"
./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs
env:
DISABLE_VALUEFLOW: 1
Expand Down
3 changes: 3 additions & 0 deletions externals/simplecpp/simplecpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3113,6 +3113,9 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::tryload(FileDat
mIdMap.emplace(fileId, data);
mData.emplace_back(data);

if (mCallback)
mCallback(*data);

return {data, true};
}

Expand Down
8 changes: 8 additions & 0 deletions externals/simplecpp/simplecpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <cctype>
#include <cstdint>
#include <cstring>
#include <functional>
#include <iosfwd>
#include <list>
#include <map>
Expand Down Expand Up @@ -505,6 +506,12 @@ namespace simplecpp {
return mData.cend();
}

using callback_type = std::function<void (FileData &)>;

void set_callback(callback_type cb) {
mCallback = std::move(cb);
}

private:
struct FileID {
#ifdef _WIN32
Expand Down Expand Up @@ -551,6 +558,7 @@ namespace simplecpp {
container_type mData;
name_map_type mNameMap;
id_map_type mIdMap;
callback_type mCallback;
};

/** Converts character literal (including prefix, but not ud-suffix) to long long value.
Expand Down
119 changes: 91 additions & 28 deletions lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ class CppCheck::CppCheckLogger : public ErrorLogger
closePlist();
}

void setRemarkComments(std::vector<RemarkComment> remarkComments)
std::vector<RemarkComment>& remarkComments()
{
mRemarkComments = std::move(remarkComments);
return mRemarkComments;
}

void setLocationMacros(const Token* startTok, const std::vector<std::string>& files)
Expand All @@ -124,17 +124,25 @@ class CppCheck::CppCheckLogger : public ErrorLogger
mErrorList.clear();
}

void openPlist(const std::string& filename, const std::vector<std::string>& files)
void openPlist(const std::string& filename)
{
mPlistFile.open(filename);
mPlistFile << ErrorLogger::plistHeader(version(), files);
mPlistFile << ErrorLogger::plistHeader(version());
}

void setPlistFilenames(std::vector<std::string> files)
{
if (mPlistFile.is_open()) {
mPlistFilenames = std::move(files);
}
}

void closePlist()
{
if (mPlistFile.is_open()) {
mPlistFile << ErrorLogger::plistFooter();
mPlistFile << ErrorLogger::plistFooter(mPlistFilenames);
mPlistFile.close();
mPlistFilenames.clear();
}
}

Expand Down Expand Up @@ -282,6 +290,7 @@ class CppCheck::CppCheckLogger : public ErrorLogger
std::map<Location, std::set<std::string>> mLocationMacros; // What macros are used on a location?

std::ofstream mPlistFile;
std::vector<std::string> mPlistFilenames;

unsigned int mExitCode{};

Expand Down Expand Up @@ -898,7 +907,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string
return checkInternal(file, cfgname, f);
}

void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector<std::string>& files)
void CppCheck::checkPlistOutput(const FileWithDetails& file)
{
if (!mSettings.plistOutput.empty()) {
const bool slashFound = file.spath().find('/') != std::string::npos;
Expand All @@ -909,7 +918,7 @@ void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector<s
// the hash is added to handle when files in different folders have the same name
const std::size_t fileNameHash = std::hash<std::string> {}(file.spath());
filename = mSettings.plistOutput + noSuffixFilename + "_" + std::to_string(fileNameHash) + ".plist";
mLogger->openPlist(filename, files);
mLogger->openPlist(filename);
}
}

Expand Down Expand Up @@ -1000,24 +1009,16 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
if (preprocessor.reportOutput(outputList, true))
return mLogger->exitcode();

if (!preprocessor.loadFiles(files))
return mLogger->exitcode();

checkPlistOutput(file, files);
checkPlistOutput(file);

std::string dumpProlog;
std::string dumpFooter;
if (mSettings.dump || !mSettings.addons.empty()) {
dumpProlog += getDumpFileContentsRawTokens(files, tokens1);
dumpFooter += getDumpFileContentsRawTokensFooter(tokens1);
}

// Parse comments and then remove them
mLogger->setRemarkComments(preprocessor.getRemarkComments());
preprocessor.addRemarkComments(mLogger->remarkComments());
preprocessor.inlineSuppressions(mSuppressions.nomsg);
if (mSettings.dump || !mSettings.addons.empty()) {
std::ostringstream oss;
mSuppressions.nomsg.dump(oss);
dumpProlog += oss.str();
}
preprocessor.removeComments();

if (!mSettings.buildDir.empty()) {
Expand All @@ -1040,19 +1041,52 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
}

// Get directives
std::list<Directive> directives = preprocessor.createDirectives();
std::list<Directive> directives;
preprocessor.createDirectives(directives);
preprocessor.simplifyPragmaAsm();

// This needs to be a linked list to allow new configurations to be discovered
// and added while iterating and checking existing configurations
std::list<std::string> configurations;
std::set<std::string> configDefines = { "__cplusplus" };

// Insert library defines
for (const auto &define : mSettings.library.defines()) {
const std::string::size_type paren = define.find("(");
const std::string::size_type space = define.find(" ");
std::string::size_type end = space;

if (paren != std::string::npos && paren < space)
end = paren;

configDefines.insert(define.substr(0, end));
}

// cppcheck-suppress danglingLifetime - false positive: lambda is owned by preprocessor
preprocessor.setLoadCallback([&](simplecpp::FileData &data) {
// Do preprocessing on included file
preprocessor.addRemarkComments(data.tokens, mLogger->remarkComments());
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 (maxConfigs > 1)
preprocessor.getConfigs(data.filename, data.tokens, configDefines, configurations);
});

preprocessor.setPlatformInfo();

// Get configurations..
std::set<std::string> configurations;
if (maxConfigs > 1) {
Timer::run("Preprocessor::getConfigs", mTimerResults, [&]() {
configurations = preprocessor.getConfigs();
configurations = { "" };
preprocessor.getConfigs(configDefines, configurations);
preprocessor.loadFiles(files);
configurations.sort();
});
} else {
configurations.insert(mSettings.userDefines);
configurations = { mSettings.userDefines };
}

if (mSettings.checkConfiguration) {
Expand Down Expand Up @@ -1089,7 +1123,6 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
createDumpFile(mSettings, file, fdump, dumpFile);
if (fdump.is_open()) {
fdump << getLibraryDumpData();
fdump << dumpProlog;
if (!mSettings.dump)
filesDeleter.addFile(dumpFile);
}
Expand Down Expand Up @@ -1259,12 +1292,20 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
}

// TODO: will not be closed if we encountered an exception
// dumped all configs, close root </dumps> element now
if (fdump.is_open()) {
// dump all filenames, raw tokens, suppressions
std::string dumpHeader = getDumpFileContentsRawTokensHeader(files);
fdump << getDumpFileContentsRawTokens(dumpHeader, dumpFooter);
mSuppressions.nomsg.dump(fdump);
// dumped all configs, close root </dumps> element now
fdump << "</dumps>" << std::endl;
fdump.close();
}

if (!mSettings.plistOutput.empty()) {
mLogger->setPlistFilenames(std::move(files));
}

executeAddons(dumpFile, file);
} catch (const TerminateException &) {
// Analysis is terminated
Expand Down Expand Up @@ -1892,16 +1933,39 @@ bool CppCheck::isPremiumCodingStandardId(const std::string& id) const {
return false;
}

std::string CppCheck::getDumpFileContentsRawTokens(const std::vector<std::string>& files, const simplecpp::TokenList& tokens1) const {
std::string CppCheck::getDumpFileContentsRawTokens(const std::vector<std::string>& files, const simplecpp::TokenList& tokens1) const
{
std::string header = getDumpFileContentsRawTokensHeader(files);
std::string footer = getDumpFileContentsRawTokensFooter(tokens1);
return getDumpFileContentsRawTokens(header, footer);
}

std::string CppCheck::getDumpFileContentsRawTokens(const std::string& header, const std::string& footer)
{
std::string dumpProlog;
dumpProlog += " <rawtokens>\n";
dumpProlog += header;
dumpProlog += footer;
dumpProlog += " </rawtokens>\n";
return dumpProlog;
}

std::string CppCheck::getDumpFileContentsRawTokensHeader(const std::vector<std::string>& files) const
{
std::string dumpProlog;
for (unsigned int i = 0; i < files.size(); ++i) {
dumpProlog += " <file index=\"";
dumpProlog += std::to_string(i);
dumpProlog += "\" name=\"";
dumpProlog += ErrorLogger::toxml(Path::getRelativePath(files[i], mSettings.basePaths));
dumpProlog += "\"/>\n";
}
return dumpProlog;
}

std::string CppCheck::getDumpFileContentsRawTokensFooter(const simplecpp::TokenList& tokens1)
{
std::string dumpProlog;
for (const simplecpp::Token *tok = tokens1.cfront(); tok; tok = tok->next) {
dumpProlog += " <tok ";

Expand All @@ -1913,7 +1977,7 @@ std::string CppCheck::getDumpFileContentsRawTokens(const std::vector<std::string
dumpProlog += std::to_string(tok->location.line);
dumpProlog += "\" ";

dumpProlog +="column=\"";
dumpProlog += "column=\"";
dumpProlog += std::to_string(tok->location.col);
dumpProlog += "\" ";

Expand All @@ -1923,6 +1987,5 @@ std::string CppCheck::getDumpFileContentsRawTokens(const std::vector<std::string

dumpProlog += "/>\n";
}
dumpProlog += " </rawtokens>\n";
return dumpProlog;
}
5 changes: 4 additions & 1 deletion lib/cppcheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ class CPPCHECKLIB CppCheck {
* @brief Get dumpfile <rawtokens> contents, this is only public for testing purposes
*/
std::string getDumpFileContentsRawTokens(const std::vector<std::string>& files, const simplecpp::TokenList& tokens1) const;
static std::string getDumpFileContentsRawTokens(const std::string& header, const std::string& footer);
std::string getDumpFileContentsRawTokensHeader(const std::vector<std::string>& files) const;
static std::string getDumpFileContentsRawTokensFooter(const simplecpp::TokenList& tokens1);

std::string getLibraryDumpData() const;

Expand Down Expand Up @@ -183,7 +186,7 @@ class CPPCHECKLIB CppCheck {
*/
unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname);

void checkPlistOutput(const FileWithDetails& file, const std::vector<std::string>& files);
void checkPlistOutput(const FileWithDetails& file);

/**
* @brief Check a file using buffer
Expand Down
9 changes: 2 additions & 7 deletions lib/errorlogger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,20 +821,15 @@ std::string ErrorLogger::toxml(const std::string &str)
return xml;
}

std::string ErrorLogger::plistHeader(const std::string &version, const std::vector<std::string> &files)
std::string ErrorLogger::plistHeader(const std::string &version)
{
std::ostringstream ostr;
ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
<< "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\r\n"
<< "<plist version=\"1.0\">\r\n"
<< "<dict>\r\n"
<< " <key>clang_version</key>\r\n"
<< "<string>cppcheck version " << version << "</string>\r\n"
<< " <key>files</key>\r\n"
<< " <array>\r\n";
for (const std::string & file : files)
ostr << " <string>" << ErrorLogger::toxml(file) << "</string>\r\n";
ostr << " </array>\r\n"
<< " <string>cppcheck version " << version << "</string>\r\n"
<< " <key>diagnostics</key>\r\n"
<< " <array>\r\n";
return ostr.str();
Expand Down
18 changes: 13 additions & 5 deletions lib/errorlogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <ctime>
#include <list>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -271,12 +272,19 @@ class CPPCHECKLIB ErrorLogger {
*/
static std::string toxml(const std::string &str);

static std::string plistHeader(const std::string &version, const std::vector<std::string> &files);
static std::string plistHeader(const std::string &version);
static std::string plistData(const ErrorMessage &msg);
static const char *plistFooter() {
return " </array>\r\n"
"</dict>\r\n"
"</plist>";
static std::string plistFooter(const std::vector<std::string>& files) {
std::ostringstream ostr;
ostr << " </array>\r\n"
<< " <key>files</key>\r\n"
<< " <array>\r\n";
for (const std::string& file : files)
ostr << " <string>" << ErrorLogger::toxml(file) << "</string>\r\n";
ostr << " </array>\r\n"
<< "</dict>\r\n"
<< "</plist>";
return ostr.str();
}

static bool isCriticalErrorId(const std::string& id) {
Expand Down
Loading
Loading