diff --git a/cfg/wxwidgets.cfg b/cfg/wxwidgets.cfg index 6d187a423..3723bd360 100644 --- a/cfg/wxwidgets.cfg +++ b/cfg/wxwidgets.cfg @@ -9385,7 +9385,7 @@ - + false diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 3eec33991..e5f5d03fa 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1565,17 +1565,29 @@ void CheckOther::checkConstPointer() continue; pointers.emplace_back(var); const Token* const parent = tok->astParent(); - bool deref = false; + enum Deref { NONE, DEREF, MEMBER } deref = NONE; if (parent && parent->isUnaryOp("*")) - deref = true; + deref = DEREF; else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok && tok != nameTok) - deref = true; + deref = DEREF; else if (Token::Match(parent, "%op%") && Token::simpleMatch(parent->astParent(), ".")) - deref = true; + deref = DEREF; + else if (Token::simpleMatch(parent, ".")) + deref = MEMBER; else if (astIsRangeBasedForDecl(tok)) continue; - if (deref) { + if (deref != NONE) { const Token* const gparent = parent->astParent(); + if (deref == MEMBER) { + if (!gparent) + continue; + if (parent->astOperand2()) { + if (parent->astOperand2()->function() && parent->astOperand2()->function()->isConst()) + continue; + if (mSettings->library.isFunctionConst(parent->astOperand2())) + continue; + } + } if (Token::Match(gparent, "%cop%") && !gparent->isUnaryOp("&") && !gparent->isUnaryOp("*")) continue; int argn = -1; diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 1872d3cab..a57057660 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -1523,7 +1523,7 @@ static void setTypes(TokenList *tokenList) } } -static void setValues(Tokenizer *tokenizer, SymbolDatabase *symbolDatabase) +static void setValues(const Tokenizer *tokenizer, const SymbolDatabase *symbolDatabase) { const Settings * const settings = tokenizer->getSettings(); diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index a0fd3e9e5..0b9578606 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1805,7 +1805,7 @@ void CppCheck::analyseWholeProgram(const std::string &buildDir, const std::mapname()) fileInfoList.push_back(check->loadFileInfoFromXml(e)); } diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 8e07d18c4..4519fa9e9 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1390,7 +1390,7 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo } } -static Token * findAstTop(Token *tok1, Token *tok2) +static Token * findAstTop(Token *tok1, const Token *tok2) { for (Token *tok = tok1; tok && (tok != tok2); tok = tok->next()) { if (tok->astParent() || tok->astOperand1() || tok->astOperand2()) { diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 46ccb6997..ff6f14000 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3966,7 +3966,7 @@ struct LifetimeStore { } } - static LifetimeStore fromFunctionArg(const Function * f, Token *tok, const Variable *var, TokenList *tokenlist, const Settings* settings, ErrorLogger *errorLogger) { + static LifetimeStore fromFunctionArg(const Function * f, const Token *tok, const Variable *var, TokenList *tokenlist, const Settings* settings, ErrorLogger *errorLogger) { if (!var) return LifetimeStore{}; if (!var->isArgument()) @@ -5039,7 +5039,7 @@ static const Token * findEndOfFunctionCallForParameter(const Token * parameterTo return nextAfterAstRightmostLeaf(parent); } -static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowAfterMove(TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings) { if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11) return; @@ -5178,7 +5178,7 @@ static const Scope* getLoopScope(const Token* tok) } // -static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings &settings) +static void valueFlowConditionExpressions(TokenList *tokenlist, const SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings &settings) { for (const Scope * scope : symboldatabase->functionScopes) { if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) { @@ -5308,7 +5308,7 @@ static std::set getVarIds(const Token* tok) return result; } -static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowSymbolic(const TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings) { for (const Scope* scope : symboldatabase->functionScopes) { for (Token* tok = const_cast(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { @@ -5401,7 +5401,7 @@ static const Token* isStrlenOf(const Token* tok, const Token* expr, int depth = static ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val); -static void valueFlowSymbolicOperators(SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowSymbolicOperators(const SymbolDatabase* symboldatabase, const Settings* settings) { for (const Scope* scope : symboldatabase->functionScopes) { for (Token* tok = const_cast(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { @@ -5512,7 +5512,7 @@ struct SymbolicInferModel : InferModel { } }; -static void valueFlowSymbolicInfer(SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowSymbolicInfer(const SymbolDatabase* symboldatabase, const Settings* settings) { for (const Scope* scope : symboldatabase->functionScopes) { for (Token* tok = const_cast(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { @@ -5792,7 +5792,7 @@ static bool intersects(const C1& c1, const C2& c2) } static void valueFlowAfterAssign(TokenList *tokenlist, - SymbolDatabase* symboldatabase, + const SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings, const std::set& skippedFunctions) @@ -5925,7 +5925,7 @@ static std::vector getVariables(const Token* tok) } static void valueFlowAfterSwap(TokenList* tokenlist, - SymbolDatabase* symboldatabase, + const SymbolDatabase* symboldatabase, ErrorLogger* errorLogger, const Settings* settings) { @@ -6098,8 +6098,8 @@ struct ConditionHandler { return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings, loc); } - void traverseCondition(TokenList* tokenlist, - SymbolDatabase* symboldatabase, + void traverseCondition(const TokenList* tokenlist, + const SymbolDatabase* symboldatabase, const Settings* settings, const std::set& skippedFunctions, const std::function& f) const @@ -6137,7 +6137,7 @@ struct ConditionHandler { } void beforeCondition(TokenList* tokenlist, - SymbolDatabase* symboldatabase, + const SymbolDatabase* symboldatabase, ErrorLogger* errorLogger, const Settings* settings, const std::set& skippedFunctions) const { @@ -6285,7 +6285,7 @@ struct ConditionHandler { } void afterCondition(TokenList* tokenlist, - SymbolDatabase* symboldatabase, + const SymbolDatabase* symboldatabase, ErrorLogger* errorLogger, const Settings* settings, const std::set& skippedFunctions) const { @@ -7040,7 +7040,7 @@ static void valueFlowForLoopSimplifyAfter(Token* fortok, nonneg int varid, const } } -static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) +static void valueFlowForLoop(TokenList *tokenlist, const SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) { for (const Scope &scope : symboldatabase->scopeList) { if (scope.type != Scope::eFor) @@ -7363,7 +7363,7 @@ static void valueFlowInjectParameter(const TokenList* tokenlist, settings); } -static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) +static void valueFlowSwitchVariable(TokenList *tokenlist, const SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) { for (const Scope &scope : symboldatabase->scopeList) { if (scope.type != Scope::ScopeType::eSwitch) @@ -7581,7 +7581,7 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat } } -static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowFunctionDefaultParameter(const TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings) { if (!tokenlist->isCPP()) return; @@ -8624,7 +8624,7 @@ static const Scope* getFunctionScope(const Scope* scope) { } static void valueFlowContainerSize(TokenList* tokenlist, - SymbolDatabase* symboldatabase, + const SymbolDatabase* symboldatabase, ErrorLogger* /*errorLogger*/, const Settings* settings, const std::set& skippedFunctions) @@ -8838,7 +8838,7 @@ struct ContainerConditionHandler : ConditionHandler { } }; -static void valueFlowDynamicBufferSize(const TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowDynamicBufferSize(const TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings) { auto getBufferSizeFromAllocFunc = [&](const Token* funcTok) -> MathLib::bigint { MathLib::bigint sizeValue = -1; @@ -9010,7 +9010,7 @@ static bool getMinMaxValues(const std::string &typestr, const Settings *settings return getMinMaxValues(&vt, settings->platform, minvalue, maxvalue); } -static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings) +static void valueFlowSafeFunctions(TokenList* tokenlist, const SymbolDatabase* symboldatabase, const Settings* settings) { for (const Scope *functionScope : symboldatabase->functionScopes) { if (!functionScope->bodyStart) diff --git a/test/testother.cpp b/test/testother.cpp index a805bbbfd..f82825b04 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -3585,6 +3585,38 @@ private: ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:2]: (style) Parameter 'p' can be declared as pointer to const. " "However it seems that 'cb' is a callback function, if 'p' is declared with const you might also need to cast function pointer(s).\n", errout.str()); + + check("void f1(std::vector* p) {\n" // #11681 + " if (p->empty()) {}\n" // warn + "}\n" + "void f2(std::vector* p) {\n" + " p->resize(0);\n" + "}\n" + "struct S {\n" + " void h1() const;\n" + " void h2();\n" + " int i;\n" + "};\n" + "void k(int&);\n" + "void g1(S* s) {\n" + " s->h1();\n" // warn + "}\n" + "void g1(S* s) {\n" + " s->h2();\n" + "}\n" + "void g1(S* s) {\n" + " if (s->i) {}\n" // warn + "}\n" + "void g2(S* s) {\n" + " s->i = 0;\n" + "}\n" + "void g3(S* s) {\n" + " k(s->i);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p' can be declared as pointer to const\n" + "[test.cpp:13]: (style) Parameter 's' can be declared as pointer to const\n" + "[test.cpp:19]: (style) Parameter 's' can be declared as pointer to const\n", + errout.str()); } void switchRedundantAssignmentTest() { @@ -7180,13 +7212,19 @@ private: " int start = x->first;\n" " int end = x->first;\n" "}"); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n" + "[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n", + errout.str()); + check("struct SW { int first; };\n" "void foo(SW* x, int i, int j) {\n" " int start = x->first;\n" " int end = x->first;\n" "}"); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'.\n" + "[test.cpp:2]: (style) Parameter 'x' can be declared as pointer to const\n", + errout.str()); + check("struct Foo { int f() const; };\n" "void test() {\n" " Foo f = Foo{};\n" @@ -7738,7 +7776,9 @@ private: "void foo(S* first) {\n" " if (first.ptr >= 0) {}\n" "}"); - ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n" + "[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7746,7 +7786,9 @@ private: "void foo(S* first, S* second) {\n" " if((first.ptr - second.ptr) >= 0) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n" + "[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7754,7 +7796,9 @@ private: "void foo(S* first) {\n" " if((first.ptr) >= 0) {}\n" "}"); - ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not.\n" + "[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7762,7 +7806,9 @@ private: "void foo(S* first, S* second) {\n" " if(0 <= first.ptr - second.ptr) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n" + "[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7770,7 +7816,9 @@ private: "void foo(S* first, S* second) {\n" " if(0 <= (first.ptr - second.ptr)) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n" + "[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7778,7 +7826,9 @@ private: "void foo(S* first, S* second) {\n" " if(first.ptr - second.ptr < 0) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n" + "[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7786,7 +7836,9 @@ private: "void foo(S* first, S* second) {\n" " if((first.ptr - second.ptr) < 0) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n" + "[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7794,7 +7846,9 @@ private: "void foo(S* first, S* second) {\n" " if(0 > first.ptr - second.ptr) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n" + "[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n", + errout.str()); check("struct S {\n" " int* ptr;\n" @@ -7802,7 +7856,9 @@ private: "void foo(S* first, S* second) {\n" " if(0 > (first.ptr - second.ptr)) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'first' can be declared as pointer to const\n" + "[test.cpp:4]: (style) Parameter 'second' can be declared as pointer to const\n", + errout.str()); check("void foo(const int* x) {\n" " if (0 <= x[0]) {}\n" @@ -7812,17 +7868,19 @@ private: check("void foo(Bar* x) {\n" " if (0 <= x.y) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str()); check("void foo(Bar* x) {\n" " if (0 <= x->y) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str()); check("void foo(Bar* x, Bar* y) {\n" " if (0 <= x->y - y->y ) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n" + "[test.cpp:1]: (style) Parameter 'y' can be declared as pointer to const\n", + errout.str()); check("void foo(const Bar* x) {\n" " if (0 > x) {}\n" @@ -7837,12 +7895,12 @@ private: check("void foo(Bar* x) {\n" " if (0 > x.y) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str()); check("void foo(Bar* x) {\n" " if (0 > x->y) {}\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'x' can be declared as pointer to const\n", errout.str()); check("void foo() {\n" " int (*t)(void *a, void *b);\n" @@ -7860,13 +7918,17 @@ private: "void packed_object_info(struct object_info *oi) {\n" " if (oi->typep < 0);\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n" + "[test.cpp:2]: (style) Parameter 'oi' can be declared as pointer to const\n", + errout.str()); check("struct object_info { int typep[10]; };\n" "void packed_object_info(struct object_info *oi) {\n" " if (oi->typep < 0);\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (style) A pointer can not be negative so it is either pointless or an error to check if it is.\n" + "[test.cpp:2]: (style) Parameter 'oi' can be declared as pointer to const\n", + errout.str()); check("struct object_info { int *typep; };\n" "void packed_object_info(struct object_info *oi) {\n"