From c30d76ba7a089950d9fa721dbdc934fa526525aa Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 28 Oct 2025 14:53:14 +0100 Subject: [PATCH] refs #13810 - fixed missing column for `invalidSuppression` --- cli/cppcheckexecutor.cpp | 2 +- lib/cppcheck.cpp | 2 +- lib/preprocessor.cpp | 105 ++++++++++++++++++++++---------------- lib/preprocessor.h | 8 +-- lib/suppressions.h | 3 ++ test/testsuppressions.cpp | 44 ++++++++-------- 6 files changed, 93 insertions(+), 71 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index c5daf5079e9..91fa42d2672 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -327,7 +327,7 @@ static bool reportUnmatchedSuppressions(const std::list callStack; if (!s.fileName.empty()) { - callStack.emplace_back(s.fileName, s.lineNumber, 0); + callStack.emplace_back(s.fileName, s.lineNumber, 0); // TODO: set column - see #13810 } errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal)); err = true; diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 1b8cc52d86b..3250cc79a13 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1162,7 +1162,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (!hasValidConfig && currCfg == *configurations.rbegin()) { // If there is no valid configuration then report error.. - preprocessor.error(tokensP.file(o->location), o->location.line, o->location.col, o->msg, o->type); + preprocessor.error(o->location, o->msg, o->type); } skipCfg = true; } diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 123ef5ca898..d94bec4956e 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -71,15 +71,13 @@ Preprocessor::Preprocessor(simplecpp::TokenList& tokens, const Settings& setting namespace { struct BadInlineSuppression { - BadInlineSuppression(std::string file, const int line, unsigned int col, std::string msg) : file(std::move(file)), line(line), col(col), errmsg(std::move(msg)) {} - std::string file; - int line; // TODO: needs to be unsigned - unsigned int col; + BadInlineSuppression(const simplecpp::Location& loc, std::string msg) : location(loc), errmsg(std::move(msg)) {} + simplecpp::Location location; std::string errmsg; }; } -static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &tokens, const simplecpp::Token *tok, std::list &inlineSuppressions, std::list &bad) +static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std::list &inlineSuppressions, std::list &bad) { const std::string cppchecksuppress("cppcheck-suppress"); @@ -92,7 +90,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token if (comment.substr(pos1, cppchecksuppress.size()) != cppchecksuppress) return false; if (pos1 + cppchecksuppress.size() >= comment.size()) { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "suppression without error ID"); + bad.emplace_back(tok->location, "suppression without error ID"); return false; } @@ -102,7 +100,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token // skip spaces after "cppcheck-suppress" and its possible prefix const std::string::size_type pos2 = comment.find_first_not_of(' ', posEndComment); if (pos2 == std::string::npos) { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "suppression without error ID"); + bad.emplace_back(tok->location, "suppression without error ID"); return false; } @@ -112,7 +110,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token if (posEndComment >= (pos1 + cppchecksuppress.size() + 1)) { const std::string suppressCmdString = comment.substr(pos1, pos2-pos1-1); if (comment.at(pos1 + cppchecksuppress.size()) != '-') { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "unknown suppression type '" + suppressCmdString + "'"); // TODO: set column + bad.emplace_back(tok->location, "unknown suppression type '" + suppressCmdString + "'"); return false; } @@ -131,7 +129,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token else if ("macro" == suppressTypeString) errorType = SuppressionList::Type::macro; else { - bad.emplace_back(tokens.file(tok->location), tok->location.line, 0, "unknown suppression type '" + suppressCmdString + "'"); // TODO: set column + bad.emplace_back(tok->location, "unknown suppression type '" + suppressCmdString + "'"); return false; } } @@ -145,11 +143,12 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token s.isInline = true; s.type = errorType; s.lineNumber = tok->location.line; + s.column = tok->location.col; } // TODO: return false? if (!errmsg.empty()) - bad.emplace_back(tokens.file(tok->location), tok->location.line, tok->location.col, std::move(errmsg)); + bad.emplace_back(tok->location, std::move(errmsg)); // TODO: report ones without ID - return false? std::copy_if(suppressions.cbegin(), suppressions.cend(), std::back_inserter(inlineSuppressions), [](const SuppressionList::Suppression& s) { @@ -165,6 +164,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token s.isInline = true; s.type = errorType; s.lineNumber = tok->location.line; + s.column = tok->location.col; // TODO: report when no ID - unreachable? if (!s.errorId.empty()) @@ -173,7 +173,7 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::TokenList &token // TODO: unreachable? // TODO: return false? if (!errmsg.empty()) - bad.emplace_back(tokens.file(tok->location), tok->location.line, tok->location.col, std::move(errmsg)); + bad.emplace_back(tok->location, std::move(errmsg)); } return true; @@ -207,7 +207,7 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } std::list inlineSuppressions; - if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad)) + if (!parseInlineSuppressionCommentToken(tok, inlineSuppressions, bad)) continue; if (!sameline(tok->previous, tok)) { @@ -216,7 +216,7 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett tok = tok->next; while (tok->comment) { - parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad); + parseInlineSuppressionCommentToken(tok, inlineSuppressions, bad); if (tok->next) { tok = tok->next; } else { @@ -248,6 +248,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) { @@ -270,6 +271,7 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett suppr.lineBegin = supprBegin->lineNumber; suppr.lineEnd = suppr.lineNumber; suppr.lineNumber = supprBegin->lineNumber; + suppr.column = supprBegin->column; suppr.type = SuppressionList::Type::block; inlineSuppressionsBlockBegin.erase(supprBegin); suppressions.addSuppression(std::move(suppr)); // TODO: check result @@ -281,8 +283,11 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } if (throwError) { - // NOLINTNEXTLINE(bugprone-use-after-move) - moved only when thrownError is false - bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "Suppress End: No matching begin"); // TODO: set column + simplecpp::Location loc; + 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 @@ -296,20 +301,31 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett suppr.thisAndNextLine = thisAndNextLine; suppr.lineNumber = tok->location.line; + suppr.column = tok->location.col; suppr.macroName = macroName; suppressions.addSuppression(std::move(suppr)); // TODO: check result } 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, 0, "File suppression should be at the top of the file"); // TODO: set column + else { + simplecpp::Location loc; + 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; + loc.fileIndex = suppr.fileIndex; + loc.line = suppr.lineNumber; + loc.col = suppr.column; // cppcheck-suppress useStlAlgorithm - bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "Suppress Begin: No matching end"); // TODO: set column + bad.emplace_back(loc, "Suppress Begin: No matching end"); + } } void Preprocessor::inlineSuppressions(SuppressionList &suppressions) @@ -322,7 +338,7 @@ void Preprocessor::inlineSuppressions(SuppressionList &suppressions) ::addInlineSuppressions(filedata->tokens, mSettings, suppressions, err); } for (const BadInlineSuppression &bad : err) { - invalidSuppression(bad.file, bad.line, bad.col, bad.errmsg); // TODO: column is always 0 + invalidSuppression(bad.location, bad.errmsg); } } @@ -865,7 +881,7 @@ const simplecpp::Output* Preprocessor::reportOutput(const simplecpp::OutputList case simplecpp::Output::ERROR: out_ret = &out; if (!startsWith(out.msg,"#error") || showerror) - error(mTokens.file(out.location), out.location.line, out.location.col, out.msg, out.type); + error(out.location, out.msg, out.type); break; case simplecpp::Output::WARNING: case simplecpp::Output::PORTABILITY_BACKSLASH: @@ -875,20 +891,20 @@ const simplecpp::Output* Preprocessor::reportOutput(const simplecpp::OutputList 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(mTokens.file(out.location), out.location.line, out.location.col, 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: out_ret = &out; - error(mTokens.file(out.location), out.location.line, out.location.col, out.msg, out.type); + 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: out_ret = &out; - error("", 0, 0, out.msg, out.type); + error({}, out.msg, out.type); break; } } @@ -923,20 +939,20 @@ static std::string simplecppErrToId(simplecpp::Output::Type type) cppcheck::unreachable(); } -void Preprocessor::error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, simplecpp::Output::Type type) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) { - error(filename, linenr, col, msg, simplecppErrToId(type)); + error(loc, msg, simplecppErrToId(type)); } -void Preprocessor::error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, const std::string& id) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) { std::list locationList; - if (!filename.empty()) { - std::string file = Path::fromNativeSeparators(filename); + if (!mTokens.file(loc).empty()) { + std::string file = Path::fromNativeSeparators(mTokens.file(loc)); if (mSettings.relativePaths) file = Path::getRelativePath(file, mSettings.basePaths); - locationList.emplace_back(file, linenr, col); + locationList.emplace_back(file, loc.line, loc.col); } mErrorLogger.reportErr(ErrorMessage(std::move(locationList), mFile0, @@ -947,15 +963,15 @@ void Preprocessor::error(const std::string &filename, unsigned int linenr, unsig } // Report that include is missing -void Preprocessor::missingInclude(const std::string &filename, unsigned int linenr, unsigned int col, 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()) { + if (!mTokens.file(loc).empty()) { // TODO: add relative path handling? - locationList.emplace_back(filename, linenr, col); + locationList.emplace_back(mTokens.file(loc), loc.line, loc.col); } ErrorMessage errmsg(std::move(locationList), mFile0, Severity::information, (headerType==SystemHeader) ? @@ -966,9 +982,9 @@ void Preprocessor::missingInclude(const std::string &filename, unsigned int line mErrorLogger.reportErr(errmsg); } -void Preprocessor::invalidSuppression(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg) +void Preprocessor::invalidSuppression(const simplecpp::Location& loc, const std::string &msg) { - error(filename, linenr, col, msg, "invalidSuppression"); + error(loc, msg, "invalidSuppression"); } void Preprocessor::getErrorMessages(ErrorLogger &errorLogger, const Settings &settings) @@ -976,14 +992,17 @@ 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, 2, "", UserHeader); - preprocessor.missingInclude("", 1, 2, "", SystemHeader); - preprocessor.error("", 1, 2, "message", simplecpp::Output::ERROR); - preprocessor.error("", 1, 2, "message", simplecpp::Output::SYNTAX_ERROR); - preprocessor.error("", 1, 2, "message", simplecpp::Output::UNHANDLED_CHAR_ERROR); - preprocessor.error("", 1, 2, "message", simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY); - preprocessor.error("", 1, 2, "message", simplecpp::Output::FILE_NOT_FOUND); - preprocessor.invalidSuppression("", 1, 2, "message"); + simplecpp::Location loc; + loc.line = 1; + loc.col = 2; + 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); + preprocessor.error(loc, "message", simplecpp::Output::FILE_NOT_FOUND); + preprocessor.invalidSuppression(loc, "message"); } void Preprocessor::dump(std::ostream &out) const diff --git a/lib/preprocessor.h b/lib/preprocessor.h index f8f213b13df..a211341691f 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -141,7 +141,7 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { const simplecpp::Output* reportOutput(const simplecpp::OutputList &outputList, bool showerror); - void error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, simplecpp::Output::Type type); + void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type); const simplecpp::Output* handleErrors(const simplecpp::OutputList &outputList); @@ -156,9 +156,9 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { SystemHeader }; - void missingInclude(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &header, HeaderTypes headerType); - void invalidSuppression(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg); - void error(const std::string &filename, unsigned int linenr, unsigned int col, const std::string &msg, const std::string& id); + void missingInclude(const simplecpp::Location& loc, const std::string &header, HeaderTypes headerType); + void invalidSuppression(const simplecpp::Location& loc, const std::string &msg); + void error(const simplecpp::Location& loc, const std::string &msg, const std::string& id); void addRemarkComments(const simplecpp::TokenList &tokens, std::vector &remarkComments) const; diff --git a/lib/suppressions.h b/lib/suppressions.h index 022a492c51f..e48a661aafb 100644 --- a/lib/suppressions.h +++ b/lib/suppressions.h @@ -149,9 +149,12 @@ class CPPCHECKLIB SuppressionList { std::string errorId; std::string fileName; std::string extraComment; + // TODO: use simplecpp::Location? + int fileIndex{}; int lineNumber = NO_LINE; // TODO: needs to be unsigned int lineBegin = NO_LINE; int lineEnd = NO_LINE; + int column{}; Type type = Type::unique; std::string symbolName; std::string macroName; diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index 1f572bd2eb2..bdea68b2ba7 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -430,7 +430,7 @@ class TestSuppressions : public TestFixture { " a++;\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:2:0]: (error) File suppression should be at the top of the file [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:2:5]: (error) File suppression should be at the top of the file [invalidSuppression]\n" "[test.cpp:4:5]: (error) Uninitialized variable: a [uninitvar]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("void f() {\n" @@ -439,7 +439,7 @@ class TestSuppressions : public TestFixture { "}\n" "// cppcheck-suppress-file uninitvar\n", "")); - ASSERT_EQUALS("[test.cpp:5:0]: (error) File suppression should be at the top of the file [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:5:1]: (error) File suppression should be at the top of the file [invalidSuppression]\n" "[test.cpp:3:5]: (error) Uninitialized variable: a [uninitvar]\n", errout_str()); ASSERT_EQUALS(0, (this->*check)("// cppcheck-suppress-file uninitvar\n" @@ -691,7 +691,7 @@ class TestSuppressions : public TestFixture { " b++;\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:2:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:2:5]: (error) Suppress Begin: No matching end [invalidSuppression]\n" "[test.cpp:4:5]: (error) Uninitialized variable: a [uninitvar]\n" "[test.cpp:6:5]: (error) Uninitialized variable: b [uninitvar]\n", errout_str()); @@ -703,7 +703,7 @@ class TestSuppressions : public TestFixture { " // cppcheck-suppress-end uninitvar\n" "}\n", "")); - ASSERT_EQUALS("[test.cpp:6:0]: (error) Suppress End: No matching begin [invalidSuppression]\n" + ASSERT_EQUALS("[test.cpp:6:5]: (error) Suppress End: No matching begin [invalidSuppression]\n" "[test.cpp:3:5]: (error) Uninitialized variable: a [uninitvar]\n" "[test.cpp:5:5]: (error) Uninitialized variable: b [uninitvar]\n", errout_str()); @@ -714,11 +714,11 @@ class TestSuppressions : public TestFixture { "void f() {}\n" "// cppcheck-suppress-end-unknown id4\n", "")); - ASSERT_EQUALS("[test.cpp:1:0]: (error) unknown suppression type 'cppcheck-suppress:' [invalidSuppression]\n" - "[test.cpp:2:0]: (error) unknown suppression type 'cppcheck-suppress-unknown' [invalidSuppression]\n" - "[test.cpp:3:0]: (error) unknown suppression type 'cppcheck-suppress-begin-unknown' [invalidSuppression]\n" - "[test.cpp:6:0]: (error) unknown suppression type 'cppcheck-suppress-end-unknown' [invalidSuppression]\n" - "[test.cpp:4:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (error) unknown suppression type 'cppcheck-suppress:' [invalidSuppression]\n" + "[test.cpp:2:1]: (error) unknown suppression type 'cppcheck-suppress-unknown' [invalidSuppression]\n" + "[test.cpp:3:1]: (error) unknown suppression type 'cppcheck-suppress-begin-unknown' [invalidSuppression]\n" + "[test.cpp:6:1]: (error) unknown suppression type 'cppcheck-suppress-end-unknown' [invalidSuppression]\n" + "[test.cpp:4:1]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress-file\n" "// cppcheck-suppress\n" @@ -731,14 +731,14 @@ class TestSuppressions : public TestFixture { "void f() {}\n" "// cppcheck-suppress-end\n", "")); - ASSERT_EQUALS("[test.cpp:1:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:2:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:3:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:4:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:6:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:7:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:10:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:8:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:2:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:3:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:4:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:6:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:7:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:10:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:8:1]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress:\n" "// cppcheck-suppress-unknown\n" @@ -748,11 +748,11 @@ class TestSuppressions : public TestFixture { "// cppcheck-suppress-end-unknown\n", "")); // TODO: actually these are all invalid types - ASSERT_EQUALS("[test.cpp:1:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:2:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:3:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:4:0]: (error) suppression without error ID [invalidSuppression]\n" - "[test.cpp:6:0]: (error) suppression without error ID [invalidSuppression]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:2:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:3:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:4:1]: (error) suppression without error ID [invalidSuppression]\n" + "[test.cpp:6:1]: (error) suppression without error ID [invalidSuppression]\n", errout_str()); ASSERT_EQUALS(1, (this->*check)("void f() {\n" " int a;\n"