diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 3d395794e..07096a2f5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -260,6 +260,11 @@ bool astIsContainerOwned(const Token* tok) { return astIsContainer(tok) && !astIsContainerView(tok); } +bool astIsRangeBasedForDecl(const Token* tok) +{ + return Token::simpleMatch(tok->astParent(), ":") && Token::simpleMatch(tok->astParent()->astParent(), "("); +} + std::string astCanonicalType(const Token *expr) { if (!expr) diff --git a/lib/astutils.h b/lib/astutils.h index 0dafe305d..d05660789 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -139,6 +139,9 @@ bool astIsContainer(const Token *tok); bool astIsContainerView(const Token* tok); bool astIsContainerOwned(const Token* tok); +/** Is given token a range-declaration in a range-based for loop */ +bool astIsRangeBasedForDecl(const Token* tok); + /** * Get canonical type of expression. const/static/etc are not included and neither *&. * For example: diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 54e2e19f8..46bc618d9 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1581,8 +1581,7 @@ void CheckOther::checkConstPointer() const Token* const nameTok = var->nameToken(); // declarations of (static) pointers are (not) split up, array declarations are never split up if (tok == nameTok && (!var->isStatic() || Token::simpleMatch(nameTok->next(), "[")) && - // range-based for loop - !(Token::simpleMatch(nameTok->astParent(), ":") && Token::simpleMatch(nameTok->astParent()->astParent(), "("))) + !astIsRangeBasedForDecl(nameTok)) continue; const ValueType* const vt = tok->valueType(); if (!vt) @@ -1598,8 +1597,8 @@ void CheckOther::checkConstPointer() deref = true; else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok && tok != nameTok) deref = true; - else if (Token::Match(parent, "%op%") && Token::simpleMatch(parent->astParent(), ".")) - deref = true; + else if (astIsRangeBasedForDecl(tok)) + continue; if (deref) { const Token* const gparent = parent->astParent(); if (Token::Match(gparent, "%cop%") && !gparent->isUnaryOp("&") && !gparent->isUnaryOp("*")) @@ -1616,7 +1615,7 @@ void CheckOther::checkConstPointer() } else if (Token::simpleMatch(gparent, "[") && gparent->astOperand2() == parent) continue; } else { - if (Token::Match(parent, "%oror%|%comp%|&&|?|!|-")) + if (Token::Match(parent, "%oror%|%comp%|&&|?|!")) continue; else if (Token::simpleMatch(parent, "(") && Token::Match(parent->astOperand1(), "if|while")) continue; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 5e31c5024..d05ce6e47 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -6212,7 +6212,7 @@ void SymbolDatabase::setValueType(Token *tok, const ValueType &valuetype) setAutoTokenProperties(autoToken); ValueType varvt(autovt); if (isconst) - varvt.constness |= (1 << varvt.pointer); + varvt.constness |= 1; setValueType(parent->previous(), varvt); Variable * var = const_cast(parent->previous()->variable()); if (var) { diff --git a/test/testother.cpp b/test/testother.cpp index f132beee2..11d4dd482 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -3124,21 +3124,36 @@ private: ASSERT_EQUALS("", errout.str()); // #10466 + check("typedef void* HWND;\n" + "void f(const std::vector&v) {\n" + " for (const auto* h : v)\n" + " if (h) {}\n" + " for (const auto& h : v)\n" + " if (h) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'h' can be declared as pointer to const\n", errout.str()); + check("void f(const std::vector& v) {\n" " for (const auto& p : v)\n" " if (p == nullptr) {}\n" " for (const auto* p : v)\n" " if (p == nullptr) {}\n" "}\n"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'p' can be declared as pointer to const\n", errout.str()); check("void f(std::vector& v) {\n" " for (const auto& p : v)\n" " if (p == nullptr) {}\n" " for (const auto* p : v)\n" " if (p == nullptr) {}\n" + " for (const int* const& p : v)\n" + " if (p == nullptr) {}\n" + " for (const int* p : v)\n" + " if (p == nullptr) {}\n" "}\n"); - ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n", errout.str()); + ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'v' can be declared as reference to const\n" + "[test.cpp:2]: (style) Variable 'p' can be declared as pointer to const\n", + errout.str()); check("void f(std::vector& v) {\n" " for (const auto& p : v)\n" @@ -3188,7 +3203,7 @@ private: "[test.cpp:4]: (style) Variable 'b' can be declared as const array\n", errout.str()); - check("typedef void* HWND;\n" + check("typedef void* HWND;\n" // #11084 "void f(const HWND h) {\n" " if (h == nullptr) {}\n" "}\n"); @@ -3217,6 +3232,19 @@ private: " (s - 1)->v();\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("void f(std::vector& v) {\n" // #11085 + " for (int* p : v) {\n" + " if (p) {}\n" + " }\n" + " for (auto* p : v) {\n" + " if (p) {}\n" + " }\n" + " v.clear();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'p' can be declared as pointer to const\n" + "[test.cpp:5]: (style) Variable 'p' can be declared as pointer to const\n", + errout.str()); } void switchRedundantAssignmentTest() { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 019b0e633..118feab0a 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -7741,6 +7741,7 @@ private: ASSERT_EQUALS("signed short &", typeOf("short values[10]; void f() { for (auto& x : values); }", "x")); ASSERT_EQUALS("signed int * &", typeOf("int* values[10]; void f() { for (auto& p : values); }", "p")); ASSERT_EQUALS("signed int * const &", typeOf("int* values[10]; void f() { for (const auto& p : values); }", "p")); + ASSERT_EQUALS("const signed int *", typeOf("int* values[10]; void f() { for (const auto* p : values); }", "p")); ASSERT_EQUALS("const signed int", typeOf("; const auto x = 3;", "x")); ASSERT_EQUALS("const signed int", typeOf("; constexpr auto x = 3;", "x")); ASSERT_EQUALS("const signed int", typeOf("; const constexpr auto x = 3;", "x"));