From cfeea3d35cb6002e83ea5299dd9e27d55fb06a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Matellanes?= Date: Sun, 7 Jan 2018 14:20:19 +0100 Subject: [PATCH] Fixed #7331: Detect copy and move constructors with default parameters (#1018) --- lib/symboldatabase.cpp | 55 +++++++++++++++++++------------------ lib/symboldatabase.h | 1 + test/testsymboldatabase.cpp | 42 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 26 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index a184cbcba..c8fd5d051 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -50,6 +50,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti createSymbolDatabaseFindAllScopes(); createSymbolDatabaseClassInfo(); createSymbolDatabaseVariableInfo(); + createSymbolDatabaseCopyAndMoveConstructors(); createSymbolDatabaseFunctionScopes(); createSymbolDatabaseClassAndStructScopes(); createSymbolDatabaseFunctionReturnTypes(); @@ -421,29 +422,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() // destructor if (function.tokenDef->previous()->str() == "~") function.type = Function::eDestructor; - - // copy/move constructor? - else if (Token::Match(function.tokenDef, "%name% ( const| %name% &|&& &| %name%| )") || - Token::Match(function.tokenDef, "%name% ( const| %name% <")) { - const Token* typeTok = function.tokenDef->tokAt(2); - if (typeTok->str() == "const") - typeTok = typeTok->next(); - if (typeTok->strAt(1) == "<") { // TODO: Remove this branch (#4710) - if (Token::Match(typeTok->linkAt(1), "> & %name%| )")) - function.type = Function::eCopyConstructor; - else if (Token::Match(typeTok->linkAt(1), "> &&|& & %name%| )")) - function.type = Function::eMoveConstructor; - else - function.type = Function::eConstructor; - } else if (typeTok->strAt(1) == "&&" || typeTok->strAt(2) == "&") - function.type = Function::eMoveConstructor; - else - function.type = Function::eCopyConstructor; - - if (typeTok->str() != function.tokenDef->str()) - function.type = Function::eConstructor; // Overwrite, if types are not identical - } - // regular constructor + // constructor of any kind else function.type = Function::eConstructor; @@ -504,9 +483,6 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() // count the number of constructors if (function.isConstructor()) scope->numConstructors++; - if (function.type == Function::eCopyConstructor || - function.type == Function::eMoveConstructor) - scope->numCopyOrMoveConstructors++; // assume implementation is inline (definition and implementation same) function.token = function.tokenDef; @@ -917,6 +893,33 @@ void SymbolDatabase::createSymbolDatabaseVariableInfo() } } +void SymbolDatabase::createSymbolDatabaseCopyAndMoveConstructors() +{ + // fill in class and struct copy/move constructors + for (std::list::iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) { + if (!scope->isClassOrStruct()) + continue; + + std::list::iterator func; + for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { + if (!func->isConstructor() || func->minArgCount() != 1) + continue; + + const Variable* firstArg = func->getArgumentVar(0); + if (firstArg->type() == scope->definedType) { + if (firstArg->isRValueReference()) + func->type = Function::eMoveConstructor; + else if (firstArg->isReference()) + func->type = Function::eCopyConstructor; + } + + if (func->type == Function::eCopyConstructor || + func->type == Function::eMoveConstructor) + scope->numCopyOrMoveConstructors++; + } + } +} + void SymbolDatabase::createSymbolDatabaseFunctionScopes() { // fill in function scopes diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 1ef6cfb85..80f7817a4 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1163,6 +1163,7 @@ private: void createSymbolDatabaseFindAllScopes(); void createSymbolDatabaseClassInfo(); void createSymbolDatabaseVariableInfo(); + void createSymbolDatabaseCopyAndMoveConstructors(); void createSymbolDatabaseFunctionScopes(); void createSymbolDatabaseClassAndStructScopes(); void createSymbolDatabaseFunctionReturnTypes(); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 69ac5cb3c..711e24d17 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -1270,6 +1270,12 @@ private: } void testConstructors() { + { + GET_SYMBOL_DB("class Foo { Foo(); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor); + ASSERT(ctor && ctor->retDef == 0); + } { GET_SYMBOL_DB("class Foo { Foo(Foo f); };"); const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); @@ -1282,18 +1288,54 @@ private: ASSERT(db && ctor && ctor->type == Function::eConstructor && ctor->isExplicit()); ASSERT(ctor && ctor->retDef == 0); } + { + GET_SYMBOL_DB("class Foo { Foo(Bar& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor); + ASSERT(ctor && ctor->retDef == 0); + } { GET_SYMBOL_DB("class Foo { Foo(Foo& f); };"); const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); ASSERT(ctor && ctor->retDef == 0); } + { + GET_SYMBOL_DB("class Foo { Foo(const Foo &f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + ASSERT(ctor && ctor->retDef == 0); + } + { + GET_SYMBOL_DB("template class Foo { Foo(Foo& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(7)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + ASSERT(ctor && ctor->retDef == 0); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo& f, int default = 0); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + ASSERT(ctor && ctor->retDef == 0); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo& f, char noDefault); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor); + ASSERT(ctor && ctor->retDef == 0); + } { GET_SYMBOL_DB("class Foo { Foo(Foo&& f); };"); const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); ASSERT(db && ctor && ctor->type == Function::eMoveConstructor); ASSERT(ctor && ctor->retDef == 0); } + { + GET_SYMBOL_DB("class Foo { Foo(Foo & & f, int default = 1, bool defaultToo = true); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eMoveConstructor); + ASSERT(ctor && ctor->retDef == 0); + } } void functionDeclarationTemplate() {