diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 3edd83663..1140b2620 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1357,25 +1357,34 @@ void CheckClass::checkConst() bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) { - const Token *tok1 = tok; + bool again = false; - while (tok->previous() && !Token::Match(tok->previous(), "}|{|;(||public:|protected:|private:|return|:|?")) + // try to find the member variable + do { - if (Token::simpleMatch(tok->previous(), "* this")) + again = false; + + if (tok->str() == "this") + { return true; - - tok = tok->previous(); + } + else if (Token::Match(tok->tokAt(-2), "%var% . %var%")) + { + tok = tok->tokAt(-2); + again = true; + } + else if (Token::Match(tok->tokAt(-2), "] . %var%")) + { + tok = tok->tokAt(-2)->link()->previous(); + again = true; + } + else if (tok->str() == "]") + { + tok = tok->link()->previous(); + again = true; + } } - - if (tok->str() == "this") - return true; - - if (Token::Match(tok, "( * %var% ) [") || (Token::Match(tok, "( * %var% ) <<") && tok1->next()->str() == "<<")) - tok = tok->tokAt(2); - - // ignore class namespace - if (tok->str() == scope->className && tok->next()->str() == "::") - tok = tok->tokAt(2); + while (again); std::list::const_iterator var; for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) @@ -1492,7 +1501,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Token *tok) (tok1->str().find("=") == 1 && tok1->str().find_first_of("") == std::string::npos)) { - if (tok1->previous()->varId() == 0 && !scope->derivedFrom.empty()) + if (tok1->next()->str() == "this") { isconst = false; break; @@ -1502,26 +1511,6 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Token *tok) isconst = false; break; } - else if (tok1->previous()->str() == "]") - { - if (isMemberVar(scope, tok1->previous()->link()->previous())) - { - isconst = false; - break; - } - } - else if (tok1->next()->str() == "this") - { - isconst = false; - break; - } - - // FIXME: I assume that a member union/struct variable is assigned. - else if (Token::Match(tok1->tokAt(-2), ". %var%")) - { - isconst = false; - break; - } } // streaming: << diff --git a/test/testclass.cpp b/test/testclass.cpp index e34b4ee69..57eacf3c7 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -176,7 +176,8 @@ private: TEST_CASE(constoperator3); TEST_CASE(constoperator4); TEST_CASE(constincdec); // increment/decrement => non-const - TEST_CASE(constassign); + TEST_CASE(constassign1); + TEST_CASE(constassign2); TEST_CASE(constincdecarray); // increment/decrement array element => non-const TEST_CASE(constassignarray); TEST_CASE(constReturnReference); @@ -5403,7 +5404,7 @@ private: ASSERT_EQUALS("[test.cpp:3]: (information) Technically the member function 'Fred::nextA' can be const.\n", errout.str()); } - void constassign() + void constassign1() { checkConst("class Fred {\n" " int a;\n" @@ -5466,6 +5467,98 @@ private: ASSERT_EQUALS("[test.cpp:3]: (information) Technically the member function 'Fred::nextA' can be const.\n", errout.str()); } + void constassign2() + { + checkConst("class Fred {\n" + " struct A { int a; } s;\n" + " void nextA() { return s.a=1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("class Fred {\n" + " struct A { int a; } s;\n" + " void nextA() { return s.a-=1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("class Fred {\n" + " struct A { int a; } s;\n" + " void nextA() { return s.a+=1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("class Fred {\n" + " struct A { int a; } s;\n" + " void nextA() { return s.a*=-1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct A { int a; } s;\n" + "class Fred {\n" + " void nextA() { return s.a=1; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (information) Technically the member function 'Fred::nextA' can be const.\n", errout.str()); + + checkConst("struct A { int a; } s;\n" + "class Fred {\n" + " void nextA() { return s.a-=1; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (information) Technically the member function 'Fred::nextA' can be const.\n", errout.str()); + + checkConst("struct A { int a; } s;\n" + "class Fred {\n" + " void nextA() { return s.a+=1; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (information) Technically the member function 'Fred::nextA' can be const.\n", errout.str()); + + checkConst("struct A { int a; } s;\n" + "class Fred {\n" + " void nextA() { return s.a*=-1; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (information) Technically the member function 'Fred::nextA' can be const.\n", errout.str()); + + checkConst("struct A { int a; } s;\n" + "class Fred {\n" + " void nextA() { return s.a/=-2; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (information) Technically the member function 'Fred::nextA' can be const.\n", errout.str()); + + checkConst("struct A { int a; };\n" + "class Fred {\n" + " A s;\n" + " void nextA() { return s.a=1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct A { int a; };\n" + "class Fred {\n" + " A s;\n" + " void nextA() { return s.a-=1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct A { int a; };\n" + "class Fred {\n" + " A s;\n" + " void nextA() { return s.a+=1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct A { int a; };\n" + "class Fred {\n" + " A s;\n" + " void nextA() { return s.a*=-1; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct A { int a; };\n" + "class Fred {\n" + " A s;\n" + " void nextA() { return s.a/=-2; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + } + // increment/decrement array element => not const void constincdecarray() {