From 55b3f0bf38795627f4cb4ea13d2a2dbbf9165632 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Thu, 4 Aug 2016 09:06:32 +0200 Subject: [PATCH] Fixed #752 (SymbolDatabase: Does not match function if redundant keywords mismatch (C++)) --- lib/checkbufferoverrun.cpp | 2 +- lib/checkuninitvar.cpp | 10 ++- lib/symboldatabase.cpp | 46 +++++++++--- lib/symboldatabase.h | 12 ++++ test/testsymboldatabase.cpp | 137 +++++++++++++++++++++++++++++++++++- 5 files changed, 189 insertions(+), 18 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index cd747f8e1..5f7be4af2 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1777,7 +1777,7 @@ CheckBufferOverrun::ArrayInfo::ArrayInfo(const Variable *var, const SymbolDataba _num.push_back(var->dimension(i)); if (var->typeEndToken()->str() == "*") _element_size = symDb->sizeOfType(var->typeEndToken()); - else if (var->typeStartToken()->str() == "struct") + else if (var->typeStartToken()->strAt(-1) == "struct") _element_size = 100; else { _element_size = symDb->sizeOfType(var->typeEndToken()); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index d307e6573..84cbcaace 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -117,12 +117,12 @@ void CheckUninitVar::checkScope(const Scope* scope) if (scope->function) { for (unsigned int i = 0; i < scope->function->argCount(); i++) { const Variable *arg = scope->function->getArgumentVar(i); - if (arg && arg->declarationId() && Token::Match(arg->typeStartToken(), "struct| %type% * %name% [,)]")) { + if (arg && arg->declarationId() && Token::Match(arg->typeStartToken(), "%type% * %name% [,)]")) { // Treat the pointer as initialized until it is assigned by malloc for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { if (Token::Match(tok, "[;{}] %varid% = %name% (", arg->declarationId()) && _settings->library.returnuninitdata.count(tok->strAt(3)) == 1U) { - if (arg->typeStartToken()->str() == "struct") + if (arg->typeStartToken()->strAt(-1) == "struct" || (arg->type() && arg->type()->isStructType())) checkStruct(tok, *arg); else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) { Alloc alloc = NO_ALLOC; @@ -138,8 +138,6 @@ void CheckUninitVar::checkScope(const Scope* scope) void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar) { const Token *typeToken = structvar.typeStartToken(); - if (typeToken->str() == "struct") - typeToken = typeToken->next(); const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase(); for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) { const Scope *scope2 = symbolDatabase->classAndStructScopes[j]; @@ -1017,9 +1015,9 @@ int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc const Variable *arg = func->getArgumentVar(argumentNumber); if (arg) { const Token *argStart = arg->typeStartToken(); - if (!address && !array && Token::Match(argStart, "struct| %type% %name%| [,)]")) + if (!address && !array && Token::Match(argStart, "%type% %name%| [,)]")) return 1; - if (pointer && !address && alloc == NO_ALLOC && Token::Match(argStart, "struct| %type% * %name% [,)]")) + if (pointer && !address && alloc == NO_ALLOC && Token::Match(argStart, "%type% * %name% [,)]")) return 1; while (argStart->previous() && argStart->previous()->isName()) argStart = argStart->previous(); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index f91339615..17a3db837 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1817,9 +1817,9 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se second = second->next(); // skip "struct" - if (first->str() == "struct") + if (first->str() == "struct" || first->str() == "enum") first = first->next(); - if (second->str() == "struct") + if (second->str() == "struct" || second->str() == "enum") second = second->next(); // skip const on type passed by value @@ -2402,7 +2402,7 @@ void SymbolDatabase::printVariable(const Variable *var, const char *indent) cons std::cout << indent << " isStlType: " << var->isStlType() << std::endl; std::cout << indent << "_type: "; if (var->type()) { - std::cout << var->type()->name(); + std::cout << var->type()->type() << " " << var->type()->name(); std::cout << " " << _tokenizer->list.fileLine(var->type()->classDef); std::cout << " " << var->type() << std::endl; } else @@ -2819,6 +2819,10 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s } while (tok->str() != "," && tok->str() != ")"); } + // skip over stuff before type + while (Token::Match(startTok, "enum|struct|const")) + startTok = startTok->next(); + argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, argType, functionScope, &symbolDatabase->_settings->library)); if (tok->str() == ")") { @@ -3183,6 +3187,10 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, con const_cast(typetok)->type(vType); } + // skip "enum" or "struct" + if (Token::Match(typestart, "enum|struct")) + typestart = typestart->next(); + addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this, lib); } @@ -3468,10 +3476,17 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty } } - const Type * type = findVariableTypeInBase(scope, typeTok); + if (scope) { + const Type * type = scope->findType(typeTok->str()); - if (type) - return type; + if (type) + return type; + + type = findVariableTypeInBase(scope, typeTok); + + if (type) + return type; + } } std::list::const_iterator type; @@ -3497,13 +3512,24 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty } if (type->enclosingScope == parent) { + // check if "enum" specified and type is enum if (typeTok->strAt(-1) == "enum") { - if (type->classDef->str() == "enum") + if (type->isEnumType()) return &(*type); - } else if (typeTok->strAt(-1) == "struct") { - if (type->classDef->str() == "struct") + else // not an enum + continue; + } + + // check if "struct" specified and type is struct + else if (typeTok->strAt(-1) == "struct") { + if (type->isStructType()) return &(*type); - } else + else // not a struct + continue; + } + + // "enum" or "struct" not specified so assume match + else return &(*type); } } diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 936553db8..f33f105b2 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -109,10 +109,22 @@ public: const std::string& name() const; + const std::string& type() const { + return classDef ? classDef->str() : emptyString; + } + + bool isClassType() const { + return classDef && classDef->str() == "class"; + } + bool isEnumType() const { return classDef && classDef->str() == "enum"; } + bool isStructType() const { + return classDef && classDef->str() == "struct"; + } + const Token *initBaseInfo(const Token *tok, const Token *tok1); const Function* getFunction(const std::string& funcName) const; diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 41785dc56..11440a2e5 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -183,6 +183,9 @@ private: TEST_CASE(functionArgs3); TEST_CASE(functionArgs4); TEST_CASE(functionArgs5); // #7650 + TEST_CASE(functionArgs6); // #7651 + TEST_CASE(functionArgs7); // #7652 + TEST_CASE(functionArgs8); // #7653 TEST_CASE(namespaces1); TEST_CASE(namespaces2); @@ -1591,7 +1594,139 @@ private: ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); if (func->argumentList.size() == 1 && func->argumentList.front().type()) { const Type * type = func->argumentList.front().type(); - ASSERT_EQUALS(true, type->classDef->str() == "enum"); + ASSERT_EQUALS(true, type->isEnumType()); + } + } + } + } + + void functionArgs6() { // #7651 + GET_SYMBOL_DB("class ABC {};\n" + "class Y {\n" + " enum ABC {A,B,C};\n" + " void f(ABC abc) {}\n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + if (db) { + const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ABC"); + ASSERT_EQUALS(true, f && f->function()); + if (f && f->function()) { + const Function *func = f->function(); + ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); + if (func->argumentList.size() == 1 && func->argumentList.front().type()) { + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isEnumType()); + } + } + } + } + + void functionArgs7() { // #7652 + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(struct AB *ab);\n" + "void bar() {\n" + " struct AB ab;\n" + " foo(&ab); \n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + if (db) { + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + if (f && f->function()) { + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + if (func->argumentList.size() == 1 && func->argumentList.front().type()) { + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + } + } + } + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(AB *ab);\n" + "void bar() {\n" + " struct AB ab;\n" + " foo(&ab); \n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + if (db) { + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + if (f && f->function()) { + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + if (func->argumentList.size() == 1 && func->argumentList.front().type()) { + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + } + } + } + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(struct AB *ab);\n" + "void bar() {\n" + " AB ab;\n" + " foo(&ab); \n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + if (db) { + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + if (f && f->function()) { + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + if (func->argumentList.size() == 1 && func->argumentList.front().type()) { + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + } + } + } + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(AB *ab);\n" + "void bar() {\n" + " AB ab;\n" + " foo(&ab); \n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + if (db) { + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + if (f && f->function()) { + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + if (func->argumentList.size() == 1 && func->argumentList.front().type()) { + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + } + } + } + } + + void functionArgs8() { // #7653 + GET_SYMBOL_DB("struct A { int i; };\n" + "struct B { double d; };\n" + "int foo(struct A a);\n" + "double foo(struct B b);\n" + "void bar() {\n" + " struct B b;\n" + " foo(b);\n" + "}"); + ASSERT_EQUALS(true, db != nullptr); + if (db) { + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( b"); + ASSERT_EQUALS(true, f && f->function()); + if (f && f->function()) { + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 4 && func->argumentList.size() == 1 && func->argumentList.front().type()); + if (func->argumentList.size() == 1 && func->argumentList.front().type()) { + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isStructType()); } } }