From f818aa237e4e1c004a2053651307b457e9c5d297 Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 21 Oct 2025 15:07:30 +0200 Subject: [PATCH 1/5] small error handling cleanup in `Preprocessor` --- lib/preprocessor.cpp | 27 +++++++++++++-------------- lib/preprocessor.h | 6 ++---- test/testpreprocessor.cpp | 12 ++++++------ 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 38e0c5201eb..46adc44a355 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -753,18 +753,10 @@ bool Preprocessor::hasErrors(const simplecpp::Output &output) return false; } -bool Preprocessor::hasErrors(const simplecpp::OutputList &outputList) -{ - const auto it = std::find_if(outputList.cbegin(), outputList.cend(), [](const simplecpp::Output &output) { - return hasErrors(output); - }); - return it != outputList.cend(); -} - -void Preprocessor::handleErrors(const simplecpp::OutputList& outputList, bool throwError) +bool Preprocessor::handleErrors(const simplecpp::OutputList& outputList, bool throwError) { const bool showerror = (!mSettings.userDefines.empty() && !mSettings.force); - reportOutput(outputList, showerror); + const bool hasError = reportOutput(outputList, showerror); if (throwError) { const auto it = std::find_if(outputList.cbegin(), outputList.cend(), [](const simplecpp::Output &output){ return hasErrors(output); @@ -773,6 +765,7 @@ void Preprocessor::handleErrors(const simplecpp::OutputList& outputList, bool th throw *it; } } + return hasError; } bool Preprocessor::loadFiles(std::vector &files) @@ -781,8 +774,7 @@ bool Preprocessor::loadFiles(std::vector &files) simplecpp::OutputList outputList; mFileCache = simplecpp::load(mTokens, files, dui, &outputList); - handleErrors(outputList, false); - return !hasErrors(outputList); + return !handleErrors(outputList, false); } void Preprocessor::removeComments() @@ -825,7 +817,7 @@ simplecpp::TokenList Preprocessor::preprocess(const std::string &cfg, std::vecto mMacroUsage = std::move(macroUsage); mIfCond = std::move(ifCond); - handleErrors(outputList, throwError); + (void)handleErrors(outputList, throwError); tokens2.removeComments(); @@ -859,11 +851,14 @@ std::string Preprocessor::getcode(const std::string &cfg, std::vector cfgcode; if (cfgs.empty()) cfgs = preprocessor.getConfigs(); From fa8287d84eab867161a0b9f766d938f6dd2db6be Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 21 Oct 2025 15:11:11 +0200 Subject: [PATCH 2/5] got rid of duplicated error reporting code in `CppCheck::checkInternal()` / cleanups [skip ci] --- lib/cppcheck.cpp | 25 +++---------------------- lib/preprocessor.h | 5 ++--- test/testpreprocessor.cpp | 13 ++----------- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 2ed39edd1ab..c5b5aa15bf6 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -977,30 +977,11 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str std::vector files; simplecpp::TokenList tokens1 = createTokenList(files, &outputList); - // If there is a syntax error, report it and stop - const auto output_it = std::find_if(outputList.cbegin(), outputList.cend(), [](const simplecpp::Output &output){ - return Preprocessor::hasErrors(output); - }); - if (output_it != outputList.cend()) { - const simplecpp::Output &output = *output_it; - std::string locfile = Path::fromNativeSeparators(output.location.file()); - if (mSettings.relativePaths) - locfile = Path::getRelativePath(locfile, mSettings.basePaths); - - ErrorMessage::FileLocation loc1(locfile, output.location.line, output.location.col); - - ErrorMessage errmsg({std::move(loc1)}, - "", // TODO: is this correct? - Severity::error, - output.msg, - "syntaxError", - Certainty::normal); - mErrorLogger.reportErr(errmsg); - return mLogger->exitcode(); - } - Preprocessor preprocessor(tokens1, mSettings, mErrorLogger, file.lang()); + if (preprocessor.reportOutput(outputList, true)) + return mLogger->exitcode(); + if (!preprocessor.loadFiles(files)) return mLogger->exitcode(); diff --git a/lib/preprocessor.h b/lib/preprocessor.h index d8078879ffc..7f63e280ed0 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -140,12 +140,11 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { */ void dump(std::ostream &out) const; - static bool hasErrors(const simplecpp::Output &output); - -protected: bool reportOutput(const simplecpp::OutputList &outputList, bool showerror); private: + static bool hasErrors(const simplecpp::Output &output); + bool handleErrors(const simplecpp::OutputList &outputList, bool throwError); static void simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList); diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 15001f3e0fc..c40ecb95edb 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -49,21 +49,12 @@ class TestPreprocessor : public TestFixture { TestPreprocessor() : TestFixture("TestPreprocessor") {} private: - class PreprocessorTest : public Preprocessor - { - friend class TestPreprocessor; - public: - PreprocessorTest(simplecpp::TokenList& tokens, const Settings& settings, ErrorLogger &errorLogger, Standards::Language lang) - : Preprocessor(tokens, settings, errorLogger, lang) - {} - }; - template std::string expandMacros(const char (&code)[size], ErrorLogger &errorLogger) const { simplecpp::OutputList outputList; std::vector files; simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", &outputList); - PreprocessorTest p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); + Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); simplecpp::TokenList tokens2 = p.preprocess("", files, true); (void)p.reportOutput(outputList, true); return tokens2.stringify(); @@ -128,7 +119,7 @@ class TestPreprocessor : public TestFixture { simplecpp::TokenList tokens(code, size, files, Path::simplifyPath(filename), &outputList); // TODO: we should be using the actual Preprocessor implementation - PreprocessorTest preprocessor(tokens, settings, errorlogger, Path::identify(tokens.getFiles()[0], false)); + Preprocessor preprocessor(tokens, settings, errorlogger, Path::identify(tokens.getFiles()[0], false)); // TODO: should be possible without a Preprocessor instance if (preprocessor.reportOutput(outputList, true)) From 5abd5dfd8a5eea973990ecc25b3be4d082cff7eb Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 28 Oct 2025 14:53:14 +0100 Subject: [PATCH 3/5] fixed error location for `simplecpp::Output` errors [skip ci] --- lib/preprocessor.cpp | 95 ++++++++++++++++++++++++++++++------------ lib/preprocessor.h | 6 +-- lib/suppressions.h | 2 + test/cli/other_test.py | 45 ++++++++++++++++++++ 4 files changed, 119 insertions(+), 29 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 46adc44a355..7f3681f6867 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -76,9 +76,8 @@ Preprocessor::Preprocessor(simplecpp::TokenList& tokens, const Settings& setting namespace { struct BadInlineSuppression { - BadInlineSuppression(std::string file, const int line, std::string msg) : file(std::move(file)), line(line), errmsg(std::move(msg)) {} - std::string file; - int line; + BadInlineSuppression(const simplecpp::Location& loc, std::string msg) : location(loc), errmsg(std::move(msg)) {} + simplecpp::Location location; std::string errmsg; }; } @@ -143,7 +142,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std: } if (!errmsg.empty()) - bad.emplace_back(tok->location.file(), tok->location.line, std::move(errmsg)); + bad.emplace_back(tok->location, std::move(errmsg)); std::copy_if(suppressions.cbegin(), suppressions.cend(), std::back_inserter(inlineSuppressions), [](const SuppressionList::Suppression& s) { return !s.errorId.empty(); @@ -163,7 +162,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std: inlineSuppressions.push_back(std::move(s)); if (!errmsg.empty()) - bad.emplace_back(tok->location.file(), tok->location.line, std::move(errmsg)); + bad.emplace_back(tok->location, std::move(errmsg)); } return true; @@ -238,6 +237,7 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett // Add the suppressions. for (SuppressionList::Suppression &suppr : inlineSuppressions) { suppr.fileName = relativeFilename; + suppr.fileIndex = tok->location.fileIndex; if (SuppressionList::Type::blockBegin == suppr.type) { @@ -271,8 +271,12 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } if (throwError) { + simplecpp::Location loc(tokens.getFiles()); // NOLINTNEXTLINE(bugprone-use-after-move) - moved only when thrownError is false - bad.emplace_back(suppr.fileName, suppr.lineNumber, "Suppress End: No matching begin"); + loc.fileIndex = suppr.fileIndex; + loc.line = suppr.lineNumber; + loc.col = suppr.column; + bad.emplace_back(loc, "Suppress End: No matching begin"); } } else if (SuppressionList::Type::unique == suppr.type || suppr.type == SuppressionList::Type::macro) { // special handling when suppressing { warnings for backwards compatibility @@ -291,15 +295,25 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } else if (SuppressionList::Type::file == suppr.type) { if (onlyComments) suppressions.addSuppression(std::move(suppr)); // TODO: check result - else - bad.emplace_back(suppr.fileName, suppr.lineNumber, "File suppression should be at the top of the file"); + else { + simplecpp::Location loc(tokens.getFiles()); + loc.fileIndex = suppr.fileIndex; + loc.line = suppr.lineNumber; + loc.col = suppr.column; + bad.emplace_back(loc, "File suppression should be at the top of the file"); + } } } } - for (const SuppressionList::Suppression & suppr: inlineSuppressionsBlockBegin) + for (const SuppressionList::Suppression & suppr: inlineSuppressionsBlockBegin) { + simplecpp::Location loc(tokens.getFiles()); + loc.fileIndex = suppr.fileIndex; + loc.line = suppr.lineNumber; + loc.col = suppr.column; // cppcheck-suppress useStlAlgorithm - bad.emplace_back(suppr.fileName, suppr.lineNumber, "Suppress Begin: No matching end"); + bad.emplace_back(loc, "Suppress Begin: No matching end"); + } } void Preprocessor::inlineSuppressions(SuppressionList &suppressions) @@ -312,7 +326,7 @@ void Preprocessor::inlineSuppressions(SuppressionList &suppressions) ::addInlineSuppressions(filedata->tokens, mSettings, suppressions, err); } for (const BadInlineSuppression &bad : err) { - error(bad.file, bad.line, bad.errmsg); + error(bad.location, bad.errmsg, simplecpp::Output::ERROR); } } @@ -860,7 +874,7 @@ bool Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh case simplecpp::Output::ERROR: hasError = true; if (!startsWith(out.msg,"#error") || showerror) - error(out.location.file(), out.location.line, out.msg); + error(out.location, out.msg, out.type); break; case simplecpp::Output::WARNING: case simplecpp::Output::PORTABILITY_BACKSLASH: @@ -869,20 +883,22 @@ bool Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh const std::string::size_type pos1 = out.msg.find_first_of("<\""); const std::string::size_type pos2 = out.msg.find_first_of(">\"", pos1 + 1U); if (pos1 < pos2 && pos2 != std::string::npos) - missingInclude(out.location.file(), out.location.line, out.msg.substr(pos1+1, pos2-pos1-1), out.msg[pos1] == '\"' ? UserHeader : SystemHeader); + missingInclude(out.location, out.msg.substr(pos1+1, pos2-pos1-1), out.msg[pos1] == '\"' ? UserHeader : SystemHeader); } break; case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY: case simplecpp::Output::SYNTAX_ERROR: case simplecpp::Output::UNHANDLED_CHAR_ERROR: hasError = true; - error(out.location.file(), out.location.line, out.msg); + error(out.location, out.msg, out.type); break; case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND: case simplecpp::Output::FILE_NOT_FOUND: case simplecpp::Output::DUI_ERROR: hasError = true; - error("", 0, out.msg); + std::vector f; + simplecpp::Location loc(f); + error(loc, out.msg, out.type); break; } } @@ -890,33 +906,56 @@ bool Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh return hasError; } -void Preprocessor::error(const std::string &filename, unsigned int linenr, const std::string &msg) +static std::string simplecppErrToId(simplecpp::Output::Type type) +{ + switch (type) { + case simplecpp::Output::ERROR: + return "preprocessorErrorDirective"; + case simplecpp::Output::SYNTAX_ERROR: + return "syntaxError"; + case simplecpp::Output::UNHANDLED_CHAR_ERROR: + return "unhandledChar"; + case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY: // TODO: add mapping + // should never occur + case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND: + case simplecpp::Output::FILE_NOT_FOUND: + case simplecpp::Output::DUI_ERROR: + // handled separately + case simplecpp::Output::MISSING_HEADER: + // no handled at all (warnings) + case simplecpp::Output::WARNING: + case simplecpp::Output::PORTABILITY_BACKSLASH: + throw std::runtime_error("unexpected type"); + } +} + +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) { std::list locationList; - if (!filename.empty()) { - std::string file = Path::fromNativeSeparators(filename); + if (!loc.file().empty()) { + std::string file = Path::fromNativeSeparators(loc.file()); if (mSettings.relativePaths) file = Path::getRelativePath(file, mSettings.basePaths); - locationList.emplace_back(file, linenr, 0); + locationList.emplace_back(file, loc.line, loc.col); } mErrorLogger.reportErr(ErrorMessage(std::move(locationList), mFile0, Severity::error, msg, - "preprocessorErrorDirective", + simplecppErrToId(type), Certainty::normal)); } // Report that include is missing -void Preprocessor::missingInclude(const std::string &filename, unsigned int linenr, const std::string &header, HeaderTypes headerType) +void Preprocessor::missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType) { if (!mSettings.checks.isEnabled(Checks::missingInclude)) return; std::list locationList; - if (!filename.empty()) { - locationList.emplace_back(filename, linenr, 0); + if (!loc.file().empty()) { + locationList.emplace_back(loc.file(), loc.line, loc.col); } ErrorMessage errmsg(std::move(locationList), mFile0, Severity::information, (headerType==SystemHeader) ? @@ -932,9 +971,13 @@ void Preprocessor::getErrorMessages(ErrorLogger &errorLogger, const Settings &se std::vector files; simplecpp::TokenList tokens(files); Preprocessor preprocessor(tokens, settings, errorLogger, Standards::Language::CPP); - preprocessor.missingInclude("", 1, "", UserHeader); - preprocessor.missingInclude("", 1, "", SystemHeader); - preprocessor.error("", 1, "#error message"); // #error .. + simplecpp::Location loc(files); + preprocessor.missingInclude(loc, "", UserHeader); + preprocessor.missingInclude(loc, "", SystemHeader); + preprocessor.error(loc, "message", simplecpp::Output::ERROR); + preprocessor.error(loc, "message", simplecpp::Output::SYNTAX_ERROR); + preprocessor.error(loc, "message", simplecpp::Output::UNHANDLED_CHAR_ERROR); + preprocessor.error(loc, "message", simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY); } void Preprocessor::dump(std::ostream &out) const diff --git a/lib/preprocessor.h b/lib/preprocessor.h index 7f63e280ed0..7163033292d 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -157,8 +157,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { SystemHeader }; - void missingInclude(const std::string &filename, unsigned int linenr, const std::string &header, HeaderTypes headerType); - void error(const std::string &filename, unsigned int linenr, const std::string &msg); + void missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType); + void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type); void addRemarkComments(const simplecpp::TokenList &tokens, std::vector &remarkComments) const; @@ -172,7 +172,7 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { simplecpp::FileDataCache mFileCache; /** filename for cpp/c file - useful when reporting errors */ - std::string mFile0; + std::string mFile0; // TODO: this is never set Standards::Language mLang{Standards::Language::None}; /** simplecpp tracking info */ diff --git a/lib/suppressions.h b/lib/suppressions.h index 8b6776560b4..4acfd5a50f6 100644 --- a/lib/suppressions.h +++ b/lib/suppressions.h @@ -151,9 +151,11 @@ class CPPCHECKLIB SuppressionList { std::string errorId; std::string fileName; std::string extraComment; + int fileIndex{}; int lineNumber = NO_LINE; int lineBegin = NO_LINE; int lineEnd = NO_LINE; + int column{}; Type type = Type::unique; std::string symbolName; std::string macroName; diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 38391ad0720..2e87e39cf1e 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -3853,3 +3853,48 @@ def test_unmatched_file(tmp_path): # #14248 / #14249 f'{lib_file}:-1:0: information: Unmatched suppression: error6 [unmatchedSuppression]' ] assert ret == 0, stdout + + +def test_simplecpp_warning(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write( + """ + #define warning "warn msg" + """) + + args = [ + '-q', + '--template=simple', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0, stdout + assert stdout.splitlines() == [] + assert stderr.splitlines() == [] + + +def test_simplecpp_unhandled_char(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write( + """ + int 你=0; + """) + + args = [ + '-q', + '--template=simple', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0, stdout + assert stdout.splitlines() == [] + assert stderr.splitlines() == [ + '{}:2:5: error: The code contains unhandled character(s) (character code=228). Neither unicode nor extended ascii is supported. [unhandledChar]'.format(test_file) # TODO: preprocessorErrorDirective seems wrong - used to be syntaxError + ] + +# TODO: test INCLUDE_NESTED_TOO_DEEPLY +# TODO: test SYNTAX_ERROR \ No newline at end of file From c973773211d3a3802cd50276a0edd97536af1a5b Mon Sep 17 00:00:00 2001 From: firewave Date: Thu, 30 Oct 2025 12:09:59 +0100 Subject: [PATCH 4/5] made some `Preprocessor` methods static [skip ci] --- lib/cppcheck.cpp | 6 ++--- lib/preprocessor.cpp | 54 +++++++++++++++++++-------------------- lib/preprocessor.h | 8 +++--- test/testpreprocessor.cpp | 9 +++---- 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index c5b5aa15bf6..658b6513ec4 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -977,11 +977,11 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str std::vector files; simplecpp::TokenList tokens1 = createTokenList(files, &outputList); - Preprocessor preprocessor(tokens1, mSettings, mErrorLogger, file.lang()); - - if (preprocessor.reportOutput(outputList, true)) + if (Preprocessor::reportOutput(mSettings, mErrorLogger,outputList, true)) return mLogger->exitcode(); + Preprocessor preprocessor(tokens1, mSettings, mErrorLogger, file.lang()); + if (!preprocessor.loadFiles(files)) return mLogger->exitcode(); diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 7f3681f6867..67e65274959 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -326,7 +326,7 @@ void Preprocessor::inlineSuppressions(SuppressionList &suppressions) ::addInlineSuppressions(filedata->tokens, mSettings, suppressions, err); } for (const BadInlineSuppression &bad : err) { - error(bad.location, bad.errmsg, simplecpp::Output::ERROR); + error(mSettings, mErrorLogger, bad.location, bad.errmsg, simplecpp::Output::ERROR); } } @@ -770,7 +770,7 @@ bool Preprocessor::hasErrors(const simplecpp::Output &output) bool Preprocessor::handleErrors(const simplecpp::OutputList& outputList, bool throwError) { const bool showerror = (!mSettings.userDefines.empty() && !mSettings.force); - const bool hasError = reportOutput(outputList, showerror); + const bool hasError = reportOutput(mSettings, mErrorLogger, outputList, showerror); if (throwError) { const auto it = std::find_if(outputList.cbegin(), outputList.cend(), [](const simplecpp::Output &output){ return hasErrors(output); @@ -865,7 +865,7 @@ std::string Preprocessor::getcode(const std::string &cfg, std::vector\"", pos1 + 1U); if (pos1 < pos2 && pos2 != std::string::npos) - missingInclude(out.location, out.msg.substr(pos1+1, pos2-pos1-1), out.msg[pos1] == '\"' ? UserHeader : SystemHeader); + missingInclude(settings, errorLogger, out.location, out.msg.substr(pos1+1, pos2-pos1-1), out.msg[pos1] == '\"' ? UserHeader : SystemHeader); } break; case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY: case simplecpp::Output::SYNTAX_ERROR: case simplecpp::Output::UNHANDLED_CHAR_ERROR: hasError = true; - error(out.location, out.msg, out.type); + error(settings, errorLogger, out.location, out.msg, out.type); break; case simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND: case simplecpp::Output::FILE_NOT_FOUND: @@ -898,7 +898,7 @@ bool Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh hasError = true; std::vector f; simplecpp::Location loc(f); - error(loc, out.msg, out.type); + error(settings, errorLogger, loc, out.msg, out.type); break; } } @@ -929,55 +929,53 @@ static std::string simplecppErrToId(simplecpp::Output::Type type) } } -void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) +void Preprocessor::error(const Settings& settings, ErrorLogger& errorLogger, const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) { std::list locationList; if (!loc.file().empty()) { std::string file = Path::fromNativeSeparators(loc.file()); - if (mSettings.relativePaths) - file = Path::getRelativePath(file, mSettings.basePaths); + if (settings.relativePaths) + file = Path::getRelativePath(file, settings.basePaths); locationList.emplace_back(file, loc.line, loc.col); } - mErrorLogger.reportErr(ErrorMessage(std::move(locationList), - mFile0, - Severity::error, - msg, - simplecppErrToId(type), - Certainty::normal)); + errorLogger.reportErr(ErrorMessage(std::move(locationList), + "", + Severity::error, + msg, + simplecppErrToId(type), + Certainty::normal)); } // Report that include is missing -void Preprocessor::missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType) +void Preprocessor::missingInclude(const Settings& settings, ErrorLogger& errorLogger, const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType) { - if (!mSettings.checks.isEnabled(Checks::missingInclude)) + if (!settings.checks.isEnabled(Checks::missingInclude)) return; std::list locationList; if (!loc.file().empty()) { locationList.emplace_back(loc.file(), loc.line, loc.col); } - ErrorMessage errmsg(std::move(locationList), mFile0, Severity::information, + ErrorMessage errmsg(std::move(locationList), "", Severity::information, (headerType==SystemHeader) ? "Include file: <" + header + "> not found. Please note: Cppcheck does not need standard library headers to get proper results." : "Include file: \"" + header + "\" not found.", (headerType==SystemHeader) ? "missingIncludeSystem" : "missingInclude", Certainty::normal); - mErrorLogger.reportErr(errmsg); + errorLogger.reportErr(errmsg); } void Preprocessor::getErrorMessages(ErrorLogger &errorLogger, const Settings &settings) { std::vector files; - simplecpp::TokenList tokens(files); - Preprocessor preprocessor(tokens, settings, errorLogger, Standards::Language::CPP); simplecpp::Location loc(files); - preprocessor.missingInclude(loc, "", UserHeader); - preprocessor.missingInclude(loc, "", SystemHeader); - preprocessor.error(loc, "message", simplecpp::Output::ERROR); - preprocessor.error(loc, "message", simplecpp::Output::SYNTAX_ERROR); - preprocessor.error(loc, "message", simplecpp::Output::UNHANDLED_CHAR_ERROR); - preprocessor.error(loc, "message", simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY); + missingInclude(settings, errorLogger, loc, "", UserHeader); + missingInclude(settings, errorLogger, loc, "", SystemHeader); + error(settings, errorLogger, loc, "message", simplecpp::Output::ERROR); + error(settings, errorLogger, loc, "message", simplecpp::Output::SYNTAX_ERROR); + error(settings, errorLogger, loc, "message", simplecpp::Output::UNHANDLED_CHAR_ERROR); + error(settings, errorLogger, loc, "message", simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY); } void Preprocessor::dump(std::ostream &out) const diff --git a/lib/preprocessor.h b/lib/preprocessor.h index 7163033292d..ee5ba63947a 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -140,7 +140,7 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { */ void dump(std::ostream &out) const; - bool reportOutput(const simplecpp::OutputList &outputList, bool showerror); + static bool reportOutput(const Settings& settings, ErrorLogger& errorLogger, const simplecpp::OutputList &outputList, bool showerror); private: static bool hasErrors(const simplecpp::Output &output); @@ -157,8 +157,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { SystemHeader }; - void missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType); - void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type); + static void missingInclude(const Settings& settings, ErrorLogger& errorLogger, const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType); + static void error(const Settings& settings, ErrorLogger& errorLogger, const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type); void addRemarkComments(const simplecpp::TokenList &tokens, std::vector &remarkComments) const; @@ -171,8 +171,6 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { 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}; /** simplecpp tracking info */ diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index c40ecb95edb..44b35151e5d 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -54,9 +54,9 @@ class TestPreprocessor : public TestFixture { simplecpp::OutputList outputList; std::vector files; simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", &outputList); + (void)Preprocessor::reportOutput(settingsDefault, errorLogger, outputList, true); Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); simplecpp::TokenList tokens2 = p.preprocess("", files, true); - (void)p.reportOutput(outputList, true); return tokens2.stringify(); } @@ -118,13 +118,12 @@ class TestPreprocessor : public TestFixture { std::vector files; simplecpp::TokenList tokens(code, size, files, Path::simplifyPath(filename), &outputList); + if (Preprocessor::reportOutput(settings, errorlogger, outputList, true)) + return {}; + // TODO: we should be using the actual Preprocessor implementation Preprocessor preprocessor(tokens, settings, errorlogger, Path::identify(tokens.getFiles()[0], false)); - // TODO: should be possible without a Preprocessor instance - if (preprocessor.reportOutput(outputList, true)) - return {}; - if (inlineSuppression) preprocessor.inlineSuppressions(*inlineSuppression); preprocessor.removeComments(); From 36f6ec632bbe281c3cbcad0729d3d19d0fc1cf5d Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 3 Nov 2025 13:38:50 +0100 Subject: [PATCH 5/5] s [skip ci] --- lib/preprocessor.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/preprocessor.h b/lib/preprocessor.h index ee5ba63947a..9c12bc1739e 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -113,12 +113,18 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { std::vector getRemarkComments() const; + /** + * @throws simplecpp::Output thrown in case of preprocessing error + */ bool loadFiles(std::vector &files); void removeComments(); void setPlatformInfo(); + /** + * @throws simplecpp::Output thrown in case of preprocessing error + */ simplecpp::TokenList preprocess(const std::string &cfg, std::vector &files, bool throwError = false); std::string getcode(const std::string &cfg, std::vector &files, bool writeLocations); @@ -145,6 +151,9 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { private: static bool hasErrors(const simplecpp::Output &output); + /** + * @throws simplecpp::Output thrown in case of preprocessing error + */ bool handleErrors(const simplecpp::OutputList &outputList, bool throwError); static void simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList);