From f1b409eb2c45345213837e4a56f289e7dca77c52 Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 9 Dec 2025 17:30:15 +0100 Subject: [PATCH 1/4] added `@throws` for `InternalError` to documentation --- lib/calculate.h | 3 +++ lib/checkleakautovar.h | 4 +++- lib/checkother.h | 3 +++ lib/clangimport.cpp | 9 +++++++++ lib/clangimport.h | 3 +++ lib/cppcheck.cpp | 3 +++ lib/errorlogger.h | 3 +++ lib/forwardanalyzer.cpp | 3 +++ lib/mathlib.h | 33 ++++++++++++++++++++++++++++++--- lib/reverseanalyzer.cpp | 3 +++ lib/symboldatabase.h | 10 ++++++++++ lib/templatesimplifier.h | 14 +++++++++----- lib/token.cpp | 3 +++ lib/token.h | 13 ++++++++++++- lib/tokenize.cpp | 6 ++++++ lib/tokenize.h | 16 ++++++++++++---- lib/tokenlist.cpp | 18 ++++++++++++++++++ lib/tokenlist.h | 3 ++- lib/valueflow.cpp | 3 +++ 19 files changed, 138 insertions(+), 15 deletions(-) diff --git a/lib/calculate.h b/lib/calculate.h index 610acd5584a..c33e37fd3b7 100644 --- a/lib/calculate.h +++ b/lib/calculate.h @@ -46,6 +46,9 @@ bool isZero(T x) return isEqual(x, T(0)); } +/** + * @throws InternalError thrown in case of unknown operator + */ template R calculate(const std::string& s, const T& x, const T& y, bool* error = nullptr) { diff --git a/lib/checkleakautovar.h b/lib/checkleakautovar.h index ba4a949bbd8..b7f57d0bd5e 100644 --- a/lib/checkleakautovar.h +++ b/lib/checkleakautovar.h @@ -119,7 +119,9 @@ class CPPCHECKLIB CheckLeakAutoVar : public Check { /** check for leaks in all scopes */ void check(); - /** check for leaks in a function scope */ + /** check for leaks in a function scope + * @throws InternalError thrown if recursion count is exceeded + */ bool checkScope(const Token * startToken, VarInfo &varInfo, std::set notzero, diff --git a/lib/checkother.h b/lib/checkother.h index b10458dc44b..28ee25cfa76 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -195,6 +195,9 @@ class CPPCHECKLIB CheckOther : public Check { void checkModuloOfOne(); + /** + * @throws InternalError thrown if largest union member could not be found + */ void checkUnionZeroInit(); void checkOverlappingWrite(); diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 87877fd629e..44d10f17c60 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -332,6 +332,9 @@ namespace clangimport { std::vector children; bool isPrologueTypedefDecl() const; + /** + * @throws InternalError thrown if AST location is invalid + */ void setLocations(TokenList &tokenList, int file, int line, int col); void dumpAst(int num = 0, int indent = 0) const; @@ -350,6 +353,9 @@ namespace clangimport { mData->mNotScope.clear(); } + /** + * @throws InternalError thrown if index is out of bounds + */ AstNodePtr getChild(int c) { if (c >= children.size()) { std::ostringstream err; @@ -361,6 +367,9 @@ namespace clangimport { return children[c]; } private: + /** + * @throws InternalError thrown if CXXForRangeStmt cannot be imported + */ Token *createTokens(TokenList &tokenList); Token *addtoken(TokenList &tokenList, const std::string &str, bool valueType=true); const ::Type *addTypeTokens(TokenList &tokenList, const std::string &str, const Scope *scope = nullptr); diff --git a/lib/clangimport.h b/lib/clangimport.h index 0475491d9af..a1c5f620983 100644 --- a/lib/clangimport.h +++ b/lib/clangimport.h @@ -29,6 +29,9 @@ class Tokenizer; namespace clangimport { + /** + * @throws InternalError thrown on incorrectly linked tokens + */ void CPPCHECKLIB parseClangAstDump(Tokenizer &tokenizer, std::istream &f); } diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index c9eaa6fadaa..11d15521ec4 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -424,6 +424,9 @@ static std::string detectPython(const CppCheck::ExecuteCmdFn &executeCommand) return ""; } +/** + * @throws InternalError thrown when execution fails + */ static std::vector executeAddon(const AddonInfo &addonInfo, const std::string &defaultPythonExe, const std::string &file, diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 8cb7cbb8c42..f8806bbbdca 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -157,6 +157,9 @@ class CPPCHECKLIB ErrorMessage { const std::string &templateLocation) const; std::string serialize() const; + /** + * @throws InternalError thrown if deserialization failed + */ void deserialize(const std::string &data); std::list callStack; diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 023a56c2496..5c97528372b 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -575,6 +575,9 @@ namespace { return updateRange(endBlock->link(), endBlock, depth); } + /** + * @throws InternalError thrown on cyclic analysis + */ Progress updateRange(Token* start, const Token* end, int depth = 20) { if (depth < 0) return Break(Analyzer::Terminate::Bail); diff --git a/lib/mathlib.h b/lib/mathlib.h index 57fd249c910..d4cc344ee7a 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -58,6 +58,9 @@ class CPPCHECKLIB MathLib { void promote(const value &v); public: + /** + * @throws InternalError thrown on invalid value + */ explicit value(const std::string &s); std::string str() const; bool isInt() const { @@ -71,10 +74,19 @@ class CPPCHECKLIB MathLib { return isFloat() ? mDoubleValue : static_cast(mIntValue); } + /** + * @throws InternalError thrown on invalid/unhandled calculation or divison by zero + */ static value calc(char op, const value &v1, const value &v2); int compare(const value &v) const; value add(int v) const; + /** + * @throws InternalError thrown if operand is not an integer + */ value shiftLeft(const value &v) const; + /** + * @throws InternalError thrown if operand is not an integer + */ value shiftRight(const value &v) const; }; @@ -82,17 +94,23 @@ class CPPCHECKLIB MathLib { /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ static bigint toBigNumber(const Token * tok); - /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ + /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() + * @throws InternalError thrown if conversion failed + */ static bigint toBigNumber(const std::string & str, const Token *tok = nullptr); /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ static biguint toBigUNumber(const Token * tok); - /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ + /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() + * @throws InternalError thrown if conversion failed + */ static biguint toBigUNumber(const std::string & str, const Token *tok = nullptr); template static std::string toString(T value) = delete; /** @brief for conversion of numeric literals */ static double toDoubleNumber(const Token * tok); - /** @brief for conversion of numeric literals */ + /** @brief for conversion of numeric literals + * @throws InternalError thrown if conversion failed + */ static double toDoubleNumber(const std::string & str, const Token * tok = nullptr); static bool isInt(const std::string & str); @@ -119,8 +137,17 @@ class CPPCHECKLIB MathLib { static std::string add(const std::string & first, const std::string & second); static std::string subtract(const std::string & first, const std::string & second); static std::string multiply(const std::string & first, const std::string & second); + /** + * @throws InternalError thrown on overflow or divison by zero + */ static std::string divide(const std::string & first, const std::string & second); + /** + * @throws InternalError thrown on division by zero + */ static std::string mod(const std::string & first, const std::string & second); + /** + * @throws InternalError thrown on unexpected action + */ static std::string calculate(const std::string & first, const std::string & second, char action); static std::string sin(const std::string & tok); diff --git a/lib/reverseanalyzer.cpp b/lib/reverseanalyzer.cpp index f1318295d6a..671426f5d2d 100644 --- a/lib/reverseanalyzer.cpp +++ b/lib/reverseanalyzer.cpp @@ -195,6 +195,9 @@ namespace { return nullptr; } + /** + * @throws InternalError thrown on cyclic analysis + */ void traverse(Token* start, const Token* end = nullptr) { if (start == end) return; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index a0e6190db73..db51328c5be 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -777,6 +777,9 @@ class CPPCHECKLIB Function { nonneg int initializedArgCount() const { return initArgCount; } + /** + * @throws InternalError thrown on unrecognized lambda + */ void addArguments(const Scope *scope); /** @brief check if this function is virtual in the base classes */ @@ -1438,6 +1441,9 @@ class CPPCHECKLIB SymbolDatabase { friend class Function; // Create symboldatabase... + /** + * @throws InternalError thrown on unhandled code + */ void createSymbolDatabaseFindAllScopes(); void createSymbolDatabaseClassInfo(); void createSymbolDatabaseVariableInfo(); @@ -1461,6 +1467,9 @@ class CPPCHECKLIB SymbolDatabase { void addClassFunction(Scope *&scope, const Token *&tok, const Token *argStart); RET_NONNULL static Function *addGlobalFunctionDecl(Scope*& scope, const Token* tok, const Token *argStart, const Token* funcStart); Function *addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart); + /** + * @throws InternalError thrown on unrecognized function + */ void addNewFunction(Scope *&scope, const Token *&tok); bool isFunction(const Token *tok, const Scope* outerScope, const Token *&funcStart, const Token *&argStart, const Token*& declEnd) const; const Type *findTypeInNested(const Token *startTok, const Scope *startScope) const; @@ -1485,6 +1494,7 @@ class CPPCHECKLIB SymbolDatabase { void validateExecutableScopes() const; /** * @brief Check variable list, e.g. variables w/o scope + * @throws InternalError thrown on variable without scope */ void validateVariables() const; diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index 35b8ab04e3a..5ac15875dad 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -150,10 +150,11 @@ class CPPCHECKLIB TemplateSimplifier { TokenAndName(Token *token, std::string scope); /** * Constructor used for declarations. - * \param token template declaration token "template < ... >" - * \param scope full qualification of template(scope) - * \param nameToken template name token "template < ... > class name" - * \param paramEnd template parameter end token ">" + * @param token template declaration token "template < ... >" + * @param scope full qualification of template(scope) + * @param nameToken template name token "template < ... > class name" + * @param paramEnd template parameter end token ">" + * @throws InternalError thrown on template issues */ TokenAndName(Token *token, std::string scope, const Token *nameToken, const Token *paramEnd); TokenAndName(const TokenAndName& other); @@ -319,6 +320,7 @@ class CPPCHECKLIB TemplateSimplifier { * @param tok start token * @return true if modifications to token-list are done. * false if no modifications are done. + * @throws InternalError thrown on division by zero in template instantiation */ static bool simplifyNumericCalculations(Token *tok, bool isTemplate = true); @@ -459,7 +461,9 @@ class CPPCHECKLIB TemplateSimplifier { */ static bool removeTemplate(Token *tok, std::map* forwardDecls = nullptr); - /** Syntax error */ + /** Syntax error + * @throws InternalError thrown unconditionally + */ NORETURN static void syntaxError(const Token *tok); static bool matchSpecialization( diff --git a/lib/token.cpp b/lib/token.cpp index 68e7838b6be..5633f291083 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -403,6 +403,9 @@ void Token::replace(Token *replaceThis, Token *start, Token *end) delete replaceThis; } +/** + * @throws InternalError thrown on unexpected command or missing varid with %varid% + */ static #if defined(__GNUC__) // GCC does not inline this by itself diff --git a/lib/token.h b/lib/token.h index 034e2d36912..5fddf510b19 100644 --- a/lib/token.h +++ b/lib/token.h @@ -902,6 +902,9 @@ class CPPCHECKLIB Token { return tok; } + /** + * @throws InternalError thrown if index is out of range + */ template )> static T *linkAtImpl(T *thisTok, int index) { @@ -1532,7 +1535,9 @@ class CPPCHECKLIB Token { } /** Updates internal property cache like _isName or _isBoolean. - Called after any mStr() modification. */ + Called after any mStr() modification. + @throws InternalError thrown if a bool literal has a varid + */ void update_property_info(); /** Update internal property cache about isStandardType() */ @@ -1548,6 +1553,9 @@ class CPPCHECKLIB Token { public: void astOperand1(Token *tok); void astOperand2(Token *tok); + /** + * @throws InternalError thrown on cyclic dependency + */ void astParent(Token* tok); Token * astOperand1() { @@ -1602,6 +1610,9 @@ class CPPCHECKLIB Token { return ret; } + /** + * @throws InternalError thrown if start or end cannot be found + */ std::pair findExpressionStartEndTokens() const; /** diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 54cc9c9a9b7..952ba4b6c00 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -669,6 +669,9 @@ namespace { return mNameToken ? mNameToken->str() : ""; } + /** + * @throws InternalError thrown if simplification failed + */ void replace(Token* tok, const std::string &originalname) { if (tok == mNameToken) return; @@ -4242,6 +4245,9 @@ void VariableMap::addVariable(const std::string& varname, bool globalNamespace) it->second = ++mVarId; } +/** + * @throws Token* thrown when closing brackets are missing + */ static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope, Standards::cstd_t cStandard) { const Token* const tok1 = tok; diff --git a/lib/tokenize.h b/lib/tokenize.h index d001c54cb10..1f32c308d14 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -376,17 +376,25 @@ class CPPCHECKLIB Tokenizer { public: - /** Syntax error */ + /** Syntax error + * @throws InternalError thrown unconditionally + */ NORETURN void syntaxError(const Token *tok, const std::string &code = "") const; - /** Syntax error. Unmatched character. */ + /** Syntax error. Unmatched character. + * @throws InternalError thrown unconditionally + */ NORETURN void unmatchedToken(const Token *tok) const; private: - /** Syntax error. C++ code in C file. */ + /** Syntax error. C++ code in C file. + * @throws InternalError thrown unconditionally + */ NORETURN void syntaxErrorC(const Token *tok, const std::string &what) const; - /** Warn about unknown macro(s), configuration is recommended */ + /** Warn about unknown macro(s), configuration is recommended # + * @throws InternalError thrown unconditionally + */ NORETURN void unknownMacroError(const Token *tok1) const; void unhandledCharLiteral(const Token *tok, const std::string& msg) const; diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 37771f02dae..2953b0c895d 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -658,6 +658,9 @@ static bool isQualifier(const Token* tok) return Token::Match(tok, "{|;"); } +/** + * @throws InternalError thrown if maximum AST depth is exceeded + */ static void compileUnaryOp(Token *&tok, AST_state& state, void (*f)(Token *&tok, AST_state& state)) { Token *unaryop = tok; @@ -694,6 +697,9 @@ static void skipGenericType(Token *&tok) } } +/** + * @throws InternalError thrown if maximum AST depth is exceeded + */ static void compileBinOp(Token *&tok, AST_state& state, void (*f)(Token *&tok, AST_state& state)) { Token *binop = tok; @@ -730,6 +736,9 @@ static void compileBinOp(Token *&tok, AST_state& state, void (*f)(Token *&tok, A static void compileExpression(Token *&tok, AST_state& state); +/** + * @throws InternalError thrown if unexpected tokens are encountered + */ static void compileTerm(Token *&tok, AST_state& state) { if (!tok) @@ -929,6 +938,9 @@ static bool isPrefixUnary(const Token* tok, bool cpp) return tok->strAt(-1) == ")" && iscast(tok->linkAt(-1), cpp); } +/** + * @throws InternalError thrown if unexpected tokens are encountered + */ static void compilePrecedence2(Token *&tok, AST_state& state) { auto doCompileScope = [&](const Token* tok) -> bool { @@ -1419,6 +1431,9 @@ static void compileComma(Token *&tok, AST_state& state) } } +/** + * @throws InternalError thrown if maximum AST depth is exceeded + */ static void compileExpression(Token *&tok, AST_state& state) { if (state.depth > AST_MAX_DEPTH) @@ -1555,6 +1570,9 @@ static Token *skipMethodDeclEnding(Token *tok) return nullptr; } +/** + * @throws InternalError thrown in case of syntax error + */ static Token * createAstAtToken(Token *tok) { const bool cpp = tok->isCpp(); diff --git a/lib/tokenlist.h b/lib/tokenlist.h index b528ebc7889..23a3acd6f6e 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -168,12 +168,13 @@ class CPPCHECKLIB TokenList { /** * Create abstract syntax tree. + * @throws InternalError thrown if encountering an infinite loop in AST creation */ void createAst() const; /** * Check abstract syntax tree. - * Throws InternalError on failure + * @throws InternalError thrown if validation fails */ void validateAst(bool print) const; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index a4e24f5ca37..7a50a5eb39b 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3789,6 +3789,9 @@ static void valueFlowSymbolicInfer(const SymbolDatabase& symboldatabase, const S } } +/** + * @throws InternalError thrown if start token precedes end token + */ template static void valueFlowForwardConst(Token* start, const Token* end, From c63f8d97c96061d427a7b63b320f5ed6528e8003 Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 15 Dec 2025 23:22:19 +0100 Subject: [PATCH 2/4] use `cppcheck::unreachable()` --- lib/errortypes.cpp | 2 +- lib/vfvalue.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/errortypes.cpp b/lib/errortypes.cpp index 2c8824c95a6..3e28e1409c8 100644 --- a/lib/errortypes.cpp +++ b/lib/errortypes.cpp @@ -69,7 +69,7 @@ std::string severityToString(Severity severity) case Severity::internal: return "internal"; } - throw InternalError(nullptr, "Unknown severity"); + cppcheck::unreachable(); } // TODO: bail out on invalid severity diff --git a/lib/vfvalue.cpp b/lib/vfvalue.cpp index cf1e07e65a3..2d1a82b32c3 100644 --- a/lib/vfvalue.cpp +++ b/lib/vfvalue.cpp @@ -129,7 +129,7 @@ namespace ValueFlow { return result; } } - throw InternalError(nullptr, "Invalid ValueFlow Value type"); + cppcheck::unreachable(); } const char *Value::toString(MoveKind moveKind) { From c2f8f40369cc22a845b8e6fbe916e152ebc31908 Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 15 Dec 2025 23:46:26 +0100 Subject: [PATCH 3/4] selfcheck.yml: adjusted `unusedFunction` suppression --- .github/workflows/selfcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 61cc1463274..3a2fd2fffc0 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -121,7 +121,7 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:193 --suppress=unusedFunction:lib/importproject.cpp:1516 --suppress=unusedFunction:lib/importproject.cpp:1540" + supprs="--suppress=unusedFunction:lib/errorlogger.h:196 --suppress=unusedFunction:lib/importproject.cpp:1516 --suppress=unusedFunction:lib/importproject.cpp:1540" ./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 From 7e6194ffc5d0cef4f3bff3f242b2866a7e9172a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Tue, 16 Dec 2025 10:36:24 +0100 Subject: [PATCH 4/4] Update lib/tokenize.h Co-authored-by: chrchr-github <78114321+chrchr-github@users.noreply.github.com> --- lib/tokenize.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenize.h b/lib/tokenize.h index 1f32c308d14..616290e7e2a 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -392,7 +392,7 @@ class CPPCHECKLIB Tokenizer { */ NORETURN void syntaxErrorC(const Token *tok, const std::string &what) const; - /** Warn about unknown macro(s), configuration is recommended # + /** Warn about unknown macro(s), configuration is recommended * @throws InternalError thrown unconditionally */ NORETURN void unknownMacroError(const Token *tok1) const;