Fixed #6538 (Symboldatabase: improve isFunction)

This commit is contained in:
Robert Reif 2015-02-24 06:11:31 +01:00 committed by Daniel Marjamäki
parent b9cc5b5c6b
commit 130ffc5752
6 changed files with 91 additions and 7 deletions

View File

@ -1288,6 +1288,57 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
(tok->previous()->isName() || tok->strAt(-1) == ">" || tok->strAt(-1) == "&" || tok->strAt(-1) == "*" || // Either a return type in front of tok
tok->strAt(-1) == "::" || tok->strAt(-1) == "~" || // or a scope qualifier in front of tok
outerScope->isClassOrStruct())) { // or a ctor/dtor
const Token* tok1 = tok->previous();
// skip over destructor "~"
if (tok1->str() == "~")
tok1 = tok1->previous();
// skip over qualification
while (Token::simpleMatch(tok1, "::")) {
if (Token::Match(tok1->tokAt(-1), "%name%"))
tok1 = tok1->tokAt(-2);
else
tok1 = tok1->tokAt(-1);
}
// skip over pointers and references
while (Token::Match(tok1, "[*&]"))
tok1 = tok1->tokAt(-1);
// skip over template
if (tok1 && tok1->str() == ">") {
if (tok1->link())
tok1 = tok1->link()->previous();
else
return false;
}
// function can't have number or variable as return type
if (tok1 && (tok1->isNumber() || tok1->varId()))
return false;
// skip over return type
if (Token::Match(tok1, "%name%"))
tok1 = tok1->previous();
// skip over qualification
while (Token::simpleMatch(tok1, "::")) {
if (Token::Match(tok1->tokAt(-1), "%name%"))
tok1 = tok1->tokAt(-2);
else
tok1 = tok1->tokAt(-1);
}
// skip over modifiers and other stuff
while (Token::Match(tok1, "const|static|extern|template|virtual|struct|class"))
tok1 = tok1->previous();
// should be at a sequence point if this is a function
if (!Token::Match(tok1, ">|{|}|;|public:|protected:|private:") && tok1)
return false;
const Token* tok2 = tok->next()->link()->next();
if (tok2 &&
(Token::Match(tok2, "const| ;|{|=") ||

View File

@ -80,6 +80,7 @@ private:
TEST_CASE(testautovar12); // ticket #5024 - crash
TEST_CASE(testautovar13); // ticket #5537 - crash
TEST_CASE(testautovar14); // ticket #4776 - assignment of function parameter, goto
TEST_CASE(testautovar15); // ticket #6538
TEST_CASE(testautovar_array1);
TEST_CASE(testautovar_array2);
TEST_CASE(testautovar_return1);
@ -390,6 +391,19 @@ private:
ASSERT_EQUALS("", errout.str());
}
void testautovar15() { // Ticket #6538
check("static const float4 darkOutline(0.05f, 0.05f, 0.05f, 0.95f);\n"
"static const float darkLuminosity = 0.05 +\n"
" 0.0722f * math::powf(darkOutline[2], 2.2);\n"
"const float4* ChooseOutlineColor(const float4& textColor) {\n"
" const float lumdiff = something;\n"
" if (lumdiff > 5.0f)\n"
" return &darkOutline;\n"
" return 0;\n"
"}", false, false);
ASSERT_EQUALS("", errout.str());
}
void testautovar_array1() {
check("void func1(int* arr[2])\n"
"{\n"

View File

@ -420,11 +420,11 @@ private:
ASSERT_THROW(checkCode("class Foo {}; class Bar : public Foo"), InternalError);
ASSERT_THROW(checkCode("YY_DECL { switch (yy_act) {\n"
" case 65: YY_BREAK\n"
" case YY_STATE_EOF(block):\n"
" yyterminate(); \n"
"} }"), InternalError); // #5663
checkCode("YY_DECL { switch (yy_act) {\n"
" case 65: YY_BREAK\n"
" case YY_STATE_EOF(block):\n"
" yyterminate(); \n"
"} }"); // #5663
}
void garbageAST() {

View File

@ -3020,7 +3020,7 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary.\n", errout.str());
// #5707
check("extern int i,j\n"
check("extern int i,j;\n"
"int foo() {\n"
" switch(i) {\n"
" default: j=1; break;\n"

View File

@ -228,6 +228,7 @@ private:
TEST_CASE(symboldatabase48); // #6417
TEST_CASE(symboldatabase49); // #6424
TEST_CASE(symboldatabase50); // #6432
TEST_CASE(symboldatabase51); // #6538
TEST_CASE(isImplicitlyVirtual);
@ -2128,6 +2129,24 @@ private:
ASSERT_EQUALS(true, db && f && f->function() && f->function()->isConstructor());
}
void symboldatabase51() { // #6538
GET_SYMBOL_DB("static const float f1 = 2 * foo1(a, b);\n"
"static const float f2 = 2 * ::foo2(a, b);\n"
"static const float f3 = 2 * std::foo3(a, b);\n"
"static const float f4 = c * foo4(a, b);\n"
"static const int i1 = 2 & foo5(a, b);\n"
"static const bool b1 = 2 > foo6(a, b);\n");
ASSERT(db != nullptr);
if (db) {
ASSERT(findFunctionByName("foo1", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo2", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo3", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo4", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo5", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo6", &db->scopeList.front()) == nullptr);
}
}
void isImplicitlyVirtual() {
{
GET_SYMBOL_DB("class Base {\n"

View File

@ -418,7 +418,7 @@ private:
"class A\n"
"{\n"
"public:\n"
" A()\n"
" A();\n"
" void a();\n"
"private:\n"
" void b();\n"