Fixed #5397 (False positive: Same expression on both sides of '&')

This commit is contained in:
Daniel Marjamäki 2014-04-12 16:06:31 +02:00
parent 7ffc313748
commit 9d51bfd015
6 changed files with 98 additions and 86 deletions

View File

@ -377,11 +377,6 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.isExplicit = true;
}
// function returning function pointer
else if (tok->str() == "(") {
function.retFuncPtr = true;
}
const Token *tok1 = tok;
// look for end of previous statement
@ -416,12 +411,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.retDef = tok1;
}
const Token *end;
if (!function.retFuncPtr)
end = function.argDef->link();
else
end = tok->link()->next()->link();
const Token *end = function.argDef->link();
// const function
if (end->next()->str() == "const")
@ -635,10 +625,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// function?
if (isFunction(tok, scope, &funcStart, &argStart)) {
bool retFuncPtr = Token::simpleMatch(argStart->link(), ") ) (");
const Token* scopeBegin = argStart->link()->next();
if (retFuncPtr)
scopeBegin = scopeBegin->next()->link()->next();
if (scopeBegin->isName()) { // Jump behind 'const' or unknown Macro
scopeBegin = scopeBegin->next();
if (scopeBegin->str() == "throw")
@ -666,7 +653,6 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
Function* function = addGlobalFunction(scope, tok, argStart, funcStart);
if (!function)
_tokenizer->syntaxError(tok);
function->retFuncPtr = retFuncPtr;
// global functions can't be const but we have tests that are
if (Token::Match(argStart->link(), ") const| noexcept")) {
@ -709,7 +695,6 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// save function prototype in database
if (newFunc) {
Function* func = addGlobalFunctionDecl(scope, tok, argStart, funcStart);
func->retFuncPtr = retFuncPtr;
if (Token::Match(argStart->link(), ") const| noexcept")) {
int arg = 2;
@ -1529,18 +1514,12 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
func->hasBody = true;
} else if (func->type != Function::eDestructor && !destructor) {
// normal function?
if (!func->retFuncPtr && (*tok)->next()->link()) {
if ((*tok)->next()->link()) {
if ((func->isConst && (*tok)->next()->link()->next()->str() == "const") ||
(!func->isConst && (*tok)->next()->link()->next()->str() != "const")) {
func->hasBody = true;
}
}
// function returning function pointer?
else if (func->retFuncPtr) {
// todo check for const
func->hasBody = true;
}
}
if (func->hasBody) {
@ -1915,7 +1894,6 @@ void SymbolDatabase::printOut(const char *title) const
std::cout << " isNoExcept: " << (func->isNoExcept ? "true" : "false") << std::endl;
std::cout << " isThrow: " << (func->isThrow ? "true" : "false") << std::endl;
std::cout << " isOperator: " << (func->isOperator ? "true" : "false") << std::endl;
std::cout << " retFuncPtr: " << (func->retFuncPtr ? "true" : "false") << std::endl;
std::cout << " noexceptArg: " << (func->noexceptArg ? func->noexceptArg->str() : "none") << std::endl;
std::cout << " throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
std::cout << " tokenDef: " << func->tokenDef->str() << " " <<_tokenizer->list.fileLine(func->tokenDef) << std::endl;

View File

@ -547,7 +547,6 @@ public:
isNoExcept(false),
isThrow(false),
isOperator(false),
retFuncPtr(false),
noexceptArg(nullptr),
throwArg(nullptr) {
}
@ -617,7 +616,6 @@ public:
bool isNoExcept; // is noexcept
bool isThrow; // is throw
bool isOperator; // is operator
bool retFuncPtr; // returns function pointer
const Token *noexceptArg;
const Token *throwArg;

View File

@ -5053,25 +5053,35 @@ void Tokenizer:: simplifyFunctionPointers()
else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
continue;
if (Token::Match(tok, "%type% *| *| ( * %var% [| ]| ) ("))
;
else if (Token::Match(tok, "%type% %type% *| *| ( * %var% [| ]| ) ("))
while (Token::Match(tok, "%type%|:: %type%|::"))
tok = tok->next();
else
Token *tok2 = (tok && tok->isName()) ? tok->next() : nullptr;
while (Token::Match(tok2, "*|&"))
tok2 = tok2->next();
if (!Token::Match(tok2, "( * %var%"))
continue;
tok2 = tok2->tokAt(2);
while (Token::Match(tok2, "%type%|:: %type%|::"))
tok2 = tok2->next();
if (!Token::Match(tok2, "%var% ) (") &&
!Token::Match(tok2, "%var% [ ] ) (") &&
!(Token::Match(tok2, "%var% (") && Token::Match(tok2->linkAt(1), ") ) (")))
continue;
while (tok->next()->str() == "*")
while (tok->str() != "(")
tok = tok->next();
// check that the declaration ends
const Token *endTok = tok->next()->link()->next()->link();
if (!Token::Match(endTok, ") ;|,|)|=|["))
const Token *endTok = tok->link()->next()->link();
if (!Token::Match(endTok, ") ;|,|)|=|[|{"))
continue;
// ok simplify this function pointer to an ordinary pointer
Token::eraseTokens(tok->next()->link(), endTok->next());
tok->next()->link()->deleteThis();
tok->deleteNext();
Token::eraseTokens(tok->link(), endTok->next());
tok->link()->deleteThis();
tok->deleteThis();
}
}

View File

@ -3945,7 +3945,7 @@ private:
const char expected[] =
"class Fred { "
""
"void ( * get ( ) ) ( ) { return test ; } "
"void * get ( ) { return test ; } "
"static void test ( ) { } "
"} ;";
@ -3962,7 +3962,7 @@ private:
const char expected[] =
"class Fred { "
""
"void * ( * get ( ) ) ( void * ) { return test ; } "
"void * * get ( ) { return test ; } "
"static void * test ( void * p ) { return p ; } "
"} ;";
@ -3979,7 +3979,7 @@ private:
const char expected[] =
"class Fred { "
""
"unsigned int * ( * get ( ) ) ( unsigned int * ) { return test ; } "
"unsigned int * * get ( ) { return test ; } "
"static unsigned int * test ( unsigned int * p ) { return p ; } "
"} ;";
@ -3997,7 +3997,7 @@ private:
const char expected[] =
"class Fred { "
""
"const unsigned int * ( * get ( ) ) ( const unsigned int * ) { return test ; } "
"const unsigned int * * get ( ) { return test ; } "
"const static unsigned int * test ( const unsigned int * p ) { return p ; } "
"} ;";
@ -4014,7 +4014,7 @@ private:
const char expected[] =
"class Fred { "
""
"void * ( * get ( int i ) ) ( void * ) { return test ; } "
"void * * get ( int i ) { return test ; } "
"static void * test ( void * p ) { return p ; } "
"} ;";
@ -5416,11 +5416,11 @@ private:
const char expected1[] = "namespace NS { "
""
"class A { "
"int ( * f ( ) ) ( ) ; "
"int * f ( ) ; "
"} ; "
"} "
"namespace NS { "
"int ( * A :: f ( ) ) ( ) { } "
"int * A :: f ( ) { } "
"}";
checkSimplifyTypedef(code1);
ASSERT_EQUALS(expected1, tok(code1));
@ -5436,10 +5436,10 @@ private:
const char expected2[] = "namespace NS { "
""
"class A { "
"int ( * f ( ) ) ( ) ; "
"int * f ( ) ; "
"} ; "
"} "
"int ( * NS :: A :: f ( ) ) ( ) { }";
"int * NS :: A :: f ( ) { }";
checkSimplifyTypedef(code2);
ASSERT_EQUALS(expected2, tok(code2));
ASSERT_EQUALS("", errout.str());
@ -5461,13 +5461,13 @@ private:
"namespace NS2 { "
""
"class A { "
"int ( * f ( ) ) ( ) ; "
"int * f ( ) ; "
"} ; "
"} "
"} "
"namespace NS1 { "
"namespace NS2 { "
"int ( * A :: f ( ) ) ( ) { } "
"int * A :: f ( ) { } "
"} "
"}";
checkSimplifyTypedef(code3);
@ -5489,12 +5489,12 @@ private:
"namespace NS2 { "
""
"class A { "
"int ( * f ( ) ) ( ) ; "
"int * f ( ) ; "
"} ; "
"} "
"} "
"namespace NS1 { "
"int ( * NS2 :: A :: f ( ) ) ( ) { } "
"int * NS2 :: A :: f ( ) { } "
"}";
checkSimplifyTypedef(code4);
ASSERT_EQUALS(expected4, tok(code4));
@ -5588,8 +5588,7 @@ private:
"};\n";
const char expected[] = "class symbol_table { "
"public: "
""
"expression_error :: error_code ( * f ) ( void * cbparam , const char * name , expression_space space ) ; "
"expression_error :: error_code * f ; "
"} ;";
checkSimplifyTypedef(code);
@ -6158,8 +6157,8 @@ private:
// The expected result..
const std::string expected("int ( * ( * t1 ) ( bool ) ) ( int , int ) ; "
"int ( * t2 ( bool ) ) ( int , int ) ; "
"int ( * t3 ( bool ) ) ( int , int ) ;");
"int * t2 ( bool ) ; "
"int * t3 ( bool ) ;");
ASSERT_EQUALS(expected, tok(code, false));
checkSimplifyTypedef(code);
@ -6194,9 +6193,9 @@ private:
// The expected result..
const std::string expected("int * t1 ; " // simplified to regular pointer
"int ( * const t2 ) ( float ) ; "
"int * const t2 ; "
"int * t3 ; " // volatile removed, gets simplified to regular pointer
"int ( * const t4 ) ( float ) ; " // volatile removed
"int * const t4 ; " // volatile removed
"int ( C :: * t5 ) ( float ) ; "
"int ( C :: * const t6 ) ( float ) ; "
"int ( C :: * t7 ) ( float ) ; " // volatile removed
@ -6226,13 +6225,13 @@ private:
// The expected result..
const std::string expected("struct Fred "
"{ "
"void ( * get1 ( ) ) ( ) { return 0 ; } "
"void ( * get2 ( ) ) ( ) { return 0 ; } "
"void ( * get3 ( ) ) ( ) ; "
"void ( * get4 ( ) ) ( ) ; "
"void * get1 ( ) { return 0 ; } "
"void * get2 ( ) { return 0 ; } "
"void * get3 ( ) ; "
"void * get4 ( ) ; "
"} ; "
"void ( * Fred :: get3 ( ) ) ( ) { return 0 ; } "
"void ( * Fred :: get4 ( ) ) ( ) { return 0 ; }");
"void * Fred :: get3 ( ) { return 0 ; } "
"void * Fred :: get4 ( ) { return 0 ; }");
ASSERT_EQUALS(expected, tok(code, false));
@ -7663,10 +7662,10 @@ private:
"};";
const char expected[] = "struct Fred "
"{ "
"void ( * get1 ( ) ) ( ) { return 0 ; } "
"void ( * get2 ( ) ) ( ) { return 0 ; } "
"void ( * get3 ( ) ) ( ) ; "
"void ( * get4 ( ) ) ( ) ; "
"void * get1 ( ) { return 0 ; } "
"void * get2 ( ) { return 0 ; } "
"void * get3 ( ) ; "
"void * get4 ( ) ; "
"} ;";
ASSERT_EQUALS(expected, tok(code, false));
}

View File

@ -712,7 +712,9 @@ private:
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->tokAt(4));
const Token * const functionToken = Token::findmatch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
@ -720,10 +722,10 @@ private:
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && function->isInline);
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
ASSERT(function && function->retDef == tokenizer.tokens()->tokAt(3));
ASSERT(function && function->retDef == functionToken->previous());
ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("func") == function);
}
@ -736,14 +738,16 @@ private:
ASSERT(db && db->scopeList.size() == 2);
if (db) {
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->tokAt(4));
const Token * const functionToken = Token::findmatch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope == nullptr);
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(4));
ASSERT(function && function->token == functionToken);
ASSERT(function && !function->hasBody);
}
}
@ -755,7 +759,9 @@ private:
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->tokAt(12));
const Token * const functionToken = Token::findmatch(tokenizer.tokens()->linkAt(2), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
@ -763,7 +769,7 @@ private:
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(12));
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && !function->isInline);
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
}
@ -776,15 +782,17 @@ private:
ASSERT(db && db->scopeList.size() == 2);
if (db) {
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->tokAt(3));
const Token * const functionToken = Token::findmatch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
const Function *function = findFunctionByName("func", &db->scopeList.front());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(3));
ASSERT(function && function->hasBody && function->retFuncPtr);
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody);
}
}
@ -795,15 +803,17 @@ private:
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->tokAt(6));
const Token * const functionToken = Token::findmatch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
ASSERT(function && function->hasBody && function->isInline && function->retFuncPtr);
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && function->isInline);
}
}
@ -814,15 +824,17 @@ private:
ASSERT(db && db->scopeList.size() == 2);
if (db) {
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->tokAt(6));
const Token * const functionToken = Token::findmatch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope == nullptr);
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(6));
ASSERT(function && !function->hasBody && function->retFuncPtr);
ASSERT(function && function->token == functionToken);
ASSERT(function && !function->hasBody);
}
}
@ -833,15 +845,17 @@ private:
ASSERT(db && db->scopeList.size() == 3);
if (db) {
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->tokAt(23));
const Token * const functionToken = Token::findmatch(tokenizer.tokens()->linkAt(2), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->tokAt(23));
ASSERT(function && function->hasBody && !function->isInline && function->retFuncPtr);
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && !function->isInline);
}
}

View File

@ -437,6 +437,7 @@ private:
TEST_CASE(functionpointer3);
TEST_CASE(functionpointer4);
TEST_CASE(functionpointer5);
TEST_CASE(functionpointer6);
TEST_CASE(removeRedundantAssignment);
@ -3881,7 +3882,7 @@ private:
void varid40() {
const char code[] ="extern \"C\" int (*a())();";
ASSERT_EQUALS("\n\n##file 0\n"
"1: int ( * a ( ) ) ( ) ;\n",
"1: int * a ( ) ;\n",
tokenizeDebugListing(code));
}
@ -7032,7 +7033,7 @@ private:
"1: struct S\n"
"2: {\n"
"3:\n"
"4: virtual void ( * getFP ( ) ) ( ) ;\n"
"4: virtual void * getFP ( ) ;\n"
"5: virtual void execute ( ) ;\n"
"6: } ;\n"
"7: void f ( ) {\n"
@ -7048,6 +7049,18 @@ private:
ASSERT_EQUALS(expected, tokenizeDebugListing(code, false));
}
void functionpointer6() {
const char code1[] = ";void (*fp(f))(int);";
const char expected1[] = "\n\n##file 0\n"
"1: ; void * fp@1 ( f ) ;\n";
ASSERT_EQUALS(expected1, tokenizeDebugListing(code1, false));
const char code2[] = ";std::string (*fp(f))(int);";
const char expected2[] = "\n\n##file 0\n"
"1: ; std :: string * fp@1 ( f ) ;\n";
ASSERT_EQUALS(expected2, tokenizeDebugListing(code2, false));
}
void removeRedundantAssignment() {
ASSERT_EQUALS("void f ( ) { }", tokenizeAndStringify("void f() { int *p, *q; p = q; }", true));
ASSERT_EQUALS("void f ( ) { }", tokenizeAndStringify("void f() { int *p = 0, *q; p = q; }", true));