Implemented support for move constructors:
- Changed behaviour of Token::function - is now also set for declarations - Resolved TODO in testclass.cpp - removed redundant code in Scope::findFunction - it is safe to call nextArgument() on functions without arguments - Use Token::function in checkother.cpp
This commit is contained in:
parent
188096665c
commit
eb2962792f
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
// 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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<int, string> foo() {}")
|
||||
|
||||
|
|
Loading…
Reference in New Issue