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:
PKEuS 2013-04-04 10:53:55 -07:00
parent 188096665c
commit eb2962792f
5 changed files with 48 additions and 30 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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),

View File

@ -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"

View File

@ -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() {}")