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())
|
else if (tok2->varId() == tok->varId())
|
||||||
error = false;
|
error = false;
|
||||||
else if (Token::Match(tok2, "%var% (") && nonLocal(tok->variable())) { // Called function might use the variable
|
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();
|
const Variable* var = tok->variable();
|
||||||
if (!var || var->isGlobal() || var->isReference() || ((!func || func->nestedIn) && tok2->strAt(-1) != ".")) // Global variable, or member function
|
if (!var || var->isGlobal() || var->isReference() || ((!func || func->nestedIn) && tok2->strAt(-1) != ".")) // Global variable, or member function
|
||||||
error = false;
|
error = false;
|
||||||
|
|
|
@ -362,30 +362,27 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
if (function.tokenDef->previous()->str() == "~")
|
if (function.tokenDef->previous()->str() == "~")
|
||||||
function.type = Function::eDestructor;
|
function.type = Function::eDestructor;
|
||||||
|
|
||||||
// copy constructor
|
// copy/move constructor?
|
||||||
else if ((Token::Match(function.tokenDef, "%var% ( const %var% & %var%| )") ||
|
else if (Token::Match(function.tokenDef, "%var% ( const| %var% &|&& &| %var%| )") ||
|
||||||
(Token::Match(function.tokenDef, "%var% ( const %var% <") &&
|
Token::Match(function.tokenDef, "%var% ( const| %var% <")) {
|
||||||
Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) &&
|
const Token* typTok = function.tokenDef->tokAt(2);
|
||||||
function.tokenDef->strAt(3) == scope->className)
|
if (typTok->str() == "const")
|
||||||
function.type = Function::eCopyConstructor;
|
typTok = typTok->next();
|
||||||
|
if (typTok->strAt(1) == "<") { // TODO: Remove this branch (#4710)
|
||||||
else if ((Token::Match(function.tokenDef, "%var% <") &&
|
if (Token::Match(typTok->linkAt(1), "> & %var%| )"))
|
||||||
Token::Match(function.tokenDef->linkAt(1), "> (const %var% & %var%| )")) &&
|
function.type = Function::eCopyConstructor;
|
||||||
function.tokenDef->linkAt(1)->strAt(3) == scope->className)
|
else if (Token::Match(typTok->linkAt(1), "> &&|& & %var%| )"))
|
||||||
function.type = Function::eCopyConstructor;
|
function.type = Function::eMoveConstructor;
|
||||||
|
else
|
||||||
// copy constructor with non-const argument
|
function.type = Function::eConstructor;
|
||||||
else if ((Token::Match(function.tokenDef, "%var% ( %var% & %var%| )") ||
|
} else if (typTok->strAt(1) == "&&" || typTok->strAt(2) == "&")
|
||||||
(Token::Match(function.tokenDef, "%var% ( %var% <") &&
|
function.type = Function::eMoveConstructor;
|
||||||
Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) &&
|
else
|
||||||
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;
|
function.type = Function::eCopyConstructor;
|
||||||
|
|
||||||
|
if (typTok->str() != function.tokenDef->str())
|
||||||
|
function.type = Function::eConstructor; // Overwrite, if types are not identical
|
||||||
|
}
|
||||||
// regular constructor
|
// regular constructor
|
||||||
else
|
else
|
||||||
function.type = Function::eConstructor;
|
function.type = Function::eConstructor;
|
||||||
|
@ -1635,6 +1632,7 @@ void SymbolDatabase::printOut(const char *title) const
|
||||||
<< _tokenizer->list.fileLine(func->tokenDef) << std::endl;
|
<< _tokenizer->list.fileLine(func->tokenDef) << std::endl;
|
||||||
std::cout << " type: " << (func->type == Function::eConstructor? "Constructor" :
|
std::cout << " type: " << (func->type == Function::eConstructor? "Constructor" :
|
||||||
func->type == Function::eCopyConstructor ? "CopyConstructor" :
|
func->type == Function::eCopyConstructor ? "CopyConstructor" :
|
||||||
|
func->type == Function::eMoveConstructor ? "MoveConstructor" :
|
||||||
func->type == Function::eOperatorEqual ? "OperatorEqual" :
|
func->type == Function::eOperatorEqual ? "OperatorEqual" :
|
||||||
func->type == Function::eDestructor ? "Destructor" :
|
func->type == Function::eDestructor ? "Destructor" :
|
||||||
func->type == Function::eFunction ? "Function" :
|
func->type == Function::eFunction ? "Function" :
|
||||||
|
@ -2394,10 +2392,6 @@ const Function* Scope::findFunction(const Token *tok) const
|
||||||
if (i->tokenDef->str() == tok->str()) {
|
if (i->tokenDef->str() == tok->str()) {
|
||||||
const Function *func = &*i;
|
const Function *func = &*i;
|
||||||
if (tok->strAt(1) == "(" && tok->tokAt(2)) {
|
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
|
// check the arguments
|
||||||
unsigned int args = 0;
|
unsigned int args = 0;
|
||||||
const Token *arg = tok->tokAt(2);
|
const Token *arg = tok->tokAt(2);
|
||||||
|
|
|
@ -432,7 +432,7 @@ private:
|
||||||
|
|
||||||
class CPPCHECKLIB Function {
|
class CPPCHECKLIB Function {
|
||||||
public:
|
public:
|
||||||
enum Type { eConstructor, eCopyConstructor, eOperatorEqual, eDestructor, eFunction };
|
enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction };
|
||||||
|
|
||||||
Function()
|
Function()
|
||||||
: tokenDef(NULL),
|
: tokenDef(NULL),
|
||||||
|
|
|
@ -5661,7 +5661,7 @@ private:
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A():m(A::pure())\n"
|
"A::A():m(A::pure())\n"
|
||||||
"{}\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"
|
checkPureVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
|
|
|
@ -132,6 +132,7 @@ private:
|
||||||
TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer);
|
TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer);
|
||||||
TEST_CASE(hasClassFunctionReturningFunctionPointer);
|
TEST_CASE(hasClassFunctionReturningFunctionPointer);
|
||||||
TEST_CASE(hasSubClassConstructor);
|
TEST_CASE(hasSubClassConstructor);
|
||||||
|
TEST_CASE(testConstructors);
|
||||||
TEST_CASE(functionDeclarationTemplate);
|
TEST_CASE(functionDeclarationTemplate);
|
||||||
TEST_CASE(functionDeclarations);
|
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() {
|
void functionDeclarationTemplate() {
|
||||||
GET_SYMBOL_DB("std::map<int, string> foo() {}")
|
GET_SYMBOL_DB("std::map<int, string> foo() {}")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue