diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 56426a979..2ba05824e 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -876,7 +876,7 @@ void CheckOther::checkRedundantAssignment() else if (tok2->varId() == tok->varId()) error = false; else if (Token::Match(tok2, "%var% (") && nonLocal(tok->variable())) { // Called function might use the variable - const Function* func = symbolDatabase->findFunction(tok2); + const Function* func = tok2->function(); const Variable* var = tok->variable(); if (!var || var->isGlobal() || var->isReference() || ((!func || func->nestedIn) && tok2->strAt(-1) != ".")) // Global variable, or member function error = false; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 5ede3d9ae..79eeb3e7c 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -362,30 +362,27 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti if (function.tokenDef->previous()->str() == "~") function.type = Function::eDestructor; - // copy constructor - else if ((Token::Match(function.tokenDef, "%var% ( const %var% & %var%| )") || - (Token::Match(function.tokenDef, "%var% ( const %var% <") && - Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) && - function.tokenDef->strAt(3) == scope->className) - function.type = Function::eCopyConstructor; - - else if ((Token::Match(function.tokenDef, "%var% <") && - Token::Match(function.tokenDef->linkAt(1), "> (const %var% & %var%| )")) && - function.tokenDef->linkAt(1)->strAt(3) == scope->className) - function.type = Function::eCopyConstructor; - - // copy constructor with non-const argument - else if ((Token::Match(function.tokenDef, "%var% ( %var% & %var%| )") || - (Token::Match(function.tokenDef, "%var% ( %var% <") && - Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) && - function.tokenDef->strAt(2) == scope->className) - function.type = Function::eCopyConstructor; - - else if ((Token::Match(function.tokenDef, "%var% <") && - Token::Match(function.tokenDef->linkAt(1), "> ( %var% & %var%| )")) && - function.tokenDef->strAt(2) == scope->className) - function.type = Function::eCopyConstructor; + // copy/move constructor? + else if (Token::Match(function.tokenDef, "%var% ( const| %var% &|&& &| %var%| )") || + Token::Match(function.tokenDef, "%var% ( const| %var% <")) { + const Token* typTok = function.tokenDef->tokAt(2); + if (typTok->str() == "const") + typTok = typTok->next(); + if (typTok->strAt(1) == "<") { // TODO: Remove this branch (#4710) + if (Token::Match(typTok->linkAt(1), "> & %var%| )")) + function.type = Function::eCopyConstructor; + else if (Token::Match(typTok->linkAt(1), "> &&|& & %var%| )")) + function.type = Function::eMoveConstructor; + else + function.type = Function::eConstructor; + } else if (typTok->strAt(1) == "&&" || typTok->strAt(2) == "&") + function.type = Function::eMoveConstructor; + else + function.type = Function::eCopyConstructor; + if (typTok->str() != function.tokenDef->str()) + function.type = Function::eConstructor; // Overwrite, if types are not identical + } // regular constructor else function.type = Function::eConstructor; @@ -1635,6 +1632,7 @@ void SymbolDatabase::printOut(const char *title) const << _tokenizer->list.fileLine(func->tokenDef) << std::endl; std::cout << " type: " << (func->type == Function::eConstructor? "Constructor" : func->type == Function::eCopyConstructor ? "CopyConstructor" : + func->type == Function::eMoveConstructor ? "MoveConstructor" : func->type == Function::eOperatorEqual ? "OperatorEqual" : func->type == Function::eDestructor ? "Destructor" : func->type == Function::eFunction ? "Function" : @@ -2394,10 +2392,6 @@ const Function* Scope::findFunction(const Token *tok) const if (i->tokenDef->str() == tok->str()) { const Function *func = &*i; if (tok->strAt(1) == "(" && tok->tokAt(2)) { - // check if function has no arguments - if (tok->strAt(2) == ")" && (func->argCount() == 0 || func->minArgCount() == 0)) - return func; - // check the arguments unsigned int args = 0; const Token *arg = tok->tokAt(2); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 6b69555a4..6af8bc6c8 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -432,7 +432,7 @@ private: class CPPCHECKLIB Function { public: - enum Type { eConstructor, eCopyConstructor, eOperatorEqual, eDestructor, eFunction }; + enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction }; Function() : tokenDef(NULL), diff --git a/test/testclass.cpp b/test/testclass.cpp index ceea1487d..8f662037e 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -5661,7 +5661,7 @@ private: "};\n" "A::A():m(A::pure())\n" "{}\n"); - TODO_ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", "", errout.str()); + ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str()); checkPureVirtualFunctionCall("class A\n" " {\n" diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 403ccec39..6935e2b1e 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -132,6 +132,7 @@ private: TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer); TEST_CASE(hasClassFunctionReturningFunctionPointer); TEST_CASE(hasSubClassConstructor); + TEST_CASE(testConstructors); TEST_CASE(functionDeclarationTemplate); TEST_CASE(functionDeclarations); @@ -729,6 +730,29 @@ private: } } + void testConstructors() { + { + GET_SYMBOL_DB("class Foo { Foo(Foo f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor && !ctor->isExplicit); + } + { + GET_SYMBOL_DB("class Foo { explicit Foo(Foo f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(4)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor && ctor->isExplicit); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo&& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eMoveConstructor); + } + } + void functionDeclarationTemplate() { GET_SYMBOL_DB("std::map foo() {}")