diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index ae93a8856..3b916c106 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1429,6 +1429,20 @@ void CheckClass::thisSubtraction() } } +const Token * findParameter(const Token *var, const Token *start, const Token * end) +{ + const Token * param = start->next(); + for (; param && param != end; param = param->next()) + { + if (param->varId()) // a function parameter + { + // check if the variable and the parameter name are the same + if (var->str() == param->str()) + return param; + } + } + return 0; +} void CheckClass::checkConst() { @@ -1490,6 +1504,9 @@ void CheckClass::checkConst() if (!tok2) break; + const Token *paramEnd = tok2; + const Token *paramStart = tok2->link(); + // is this a non-const function that is implemented inline? if (Token::simpleMatch(tok2, ") {")) { @@ -1513,6 +1530,24 @@ void CheckClass::checkConst() (tok3->str().find("=") == 1 && tok3->str().find_first_of("<>") == std::string::npos)) { + if (tok3->str() == "=") // assignment.. = + { + const Token * param = findParameter(tok3->previous(), paramStart, paramEnd); + if (param) + { + // assignment to function argument reference can be const + // f(type & x) { x = something; } + if (param->tokAt(-1)->str() == "&") + continue; + + // assignment to function argument pointer can be const + // f(type * x) { *x = something; } + else if ((param->tokAt(-1)->str() == "*") && + (tok3->tokAt(-2)->str() == "*")) + continue; + } + } + isconst = false; break; } diff --git a/test/testclass.cpp b/test/testclass.cpp index 6351e6f6a..93a83f7fd 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -82,6 +82,8 @@ private: // can member function be made const TEST_CASE(const1); + TEST_CASE(const2); + TEST_CASE(const3); TEST_CASE(constoperator); // operator< can often be const TEST_CASE(constincdec); // increment/decrement => non-const TEST_CASE(constReturnReference); @@ -1624,6 +1626,104 @@ private: ASSERT_EQUALS("", errout.str()); } + void const2() + { + // ticket 1344 + // assignment to variable can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo() { s = ""; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + // assignment to function argument reference can be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string & a) { a = s; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) The function 'Fred::foo' can be const\n", errout.str()); + + // assignment to variable can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string & a) { s = a; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + // assignment to function argument references can be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string & a, std::string & b) { a = s; b = s; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) The function 'Fred::foo' can be const\n", errout.str()); + + // assignment to variable, can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string & a, std::string & b) { s = a; s = b; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + // assignment to variable, can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string & a, std::string & b) { s = a; b = s; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + // assignment to variable, can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string & a, std::string & b) { a = s; s = b; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + } + + void const3() + { + // assignment to function argument pointer can be const + checkConst("class Fred {\n" + " int s;\n" + " void foo(int * a) { *a = s; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) The function 'Fred::foo' can be const\n", errout.str()); + + // assignment to variable, can't be const + checkConst("class Fred {\n" + " int s;\n" + " void foo(int * a) { s = *a; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + // assignment to function argument pointers can be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string * a, std::string * b) { *a = s; *b = s; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) The function 'Fred::foo' can be const\n", errout.str()); + + // assignment to variable, can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string * a, std::string * b) { s = *a; s = *b; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + // assignment to variable, can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string * a, std::string * b) { s = *a; *b = s; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + // assignment to variable, can't be const + checkConst("class Fred {\n" + " std::string s;\n" + " void foo(std::string * a, std::string * b) { *a = s; s = b; }\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + } + // operator< can often be const void constoperator() {