Fixed #752 (SymbolDatabase: Does not match function if redundant keywords mismatch (C++))

This commit is contained in:
Robert Reif 2016-08-04 09:06:32 +02:00 committed by Daniel Marjamäki
parent 6ca76ff965
commit 55b3f0bf38
5 changed files with 189 additions and 18 deletions

View File

@ -1777,7 +1777,7 @@ CheckBufferOverrun::ArrayInfo::ArrayInfo(const Variable *var, const SymbolDataba
_num.push_back(var->dimension(i)); _num.push_back(var->dimension(i));
if (var->typeEndToken()->str() == "*") if (var->typeEndToken()->str() == "*")
_element_size = symDb->sizeOfType(var->typeEndToken()); _element_size = symDb->sizeOfType(var->typeEndToken());
else if (var->typeStartToken()->str() == "struct") else if (var->typeStartToken()->strAt(-1) == "struct")
_element_size = 100; _element_size = 100;
else { else {
_element_size = symDb->sizeOfType(var->typeEndToken()); _element_size = symDb->sizeOfType(var->typeEndToken());

View File

@ -117,12 +117,12 @@ void CheckUninitVar::checkScope(const Scope* scope)
if (scope->function) { if (scope->function) {
for (unsigned int i = 0; i < scope->function->argCount(); i++) { for (unsigned int i = 0; i < scope->function->argCount(); i++) {
const Variable *arg = scope->function->getArgumentVar(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 // Treat the pointer as initialized until it is assigned by malloc
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
if (Token::Match(tok, "[;{}] %varid% = %name% (", arg->declarationId()) && if (Token::Match(tok, "[;{}] %varid% = %name% (", arg->declarationId()) &&
_settings->library.returnuninitdata.count(tok->strAt(3)) == 1U) { _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); checkStruct(tok, *arg);
else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) { else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) {
Alloc alloc = NO_ALLOC; Alloc alloc = NO_ALLOC;
@ -138,8 +138,6 @@ void CheckUninitVar::checkScope(const Scope* scope)
void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar) void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar)
{ {
const Token *typeToken = structvar.typeStartToken(); const Token *typeToken = structvar.typeStartToken();
if (typeToken->str() == "struct")
typeToken = typeToken->next();
const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase();
for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) { for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) {
const Scope *scope2 = symbolDatabase->classAndStructScopes[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); const Variable *arg = func->getArgumentVar(argumentNumber);
if (arg) { if (arg) {
const Token *argStart = arg->typeStartToken(); const Token *argStart = arg->typeStartToken();
if (!address && !array && Token::Match(argStart, "struct| %type% %name%| [,)]")) if (!address && !array && Token::Match(argStart, "%type% %name%| [,)]"))
return 1; 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; return 1;
while (argStart->previous() && argStart->previous()->isName()) while (argStart->previous() && argStart->previous()->isName())
argStart = argStart->previous(); argStart = argStart->previous();

View File

@ -1817,9 +1817,9 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
second = second->next(); second = second->next();
// skip "struct" // skip "struct"
if (first->str() == "struct") if (first->str() == "struct" || first->str() == "enum")
first = first->next(); first = first->next();
if (second->str() == "struct") if (second->str() == "struct" || second->str() == "enum")
second = second->next(); second = second->next();
// skip const on type passed by value // 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 << " isStlType: " << var->isStlType() << std::endl;
std::cout << indent << "_type: "; std::cout << indent << "_type: ";
if (var->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 << " " << _tokenizer->list.fileLine(var->type()->classDef);
std::cout << " " << var->type() << std::endl; std::cout << " " << var->type() << std::endl;
} else } else
@ -2819,6 +2819,10 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
} while (tok->str() != "," && tok->str() != ")"); } 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)); argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, argType, functionScope, &symbolDatabase->_settings->library));
if (tok->str() == ")") { if (tok->str() == ")") {
@ -3183,6 +3187,10 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, con
const_cast<Token *>(typetok)->type(vType); const_cast<Token *>(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); 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) if (type)
return type; return type;
type = findVariableTypeInBase(scope, typeTok);
if (type)
return type;
}
} }
std::list<Type>::const_iterator type; std::list<Type>::const_iterator type;
@ -3497,13 +3512,24 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty
} }
if (type->enclosingScope == parent) { if (type->enclosingScope == parent) {
// check if "enum" specified and type is enum
if (typeTok->strAt(-1) == "enum") { if (typeTok->strAt(-1) == "enum") {
if (type->classDef->str() == "enum") if (type->isEnumType())
return &(*type); return &(*type);
} else if (typeTok->strAt(-1) == "struct") { else // not an enum
if (type->classDef->str() == "struct") continue;
}
// check if "struct" specified and type is struct
else if (typeTok->strAt(-1) == "struct") {
if (type->isStructType())
return &(*type); return &(*type);
} else else // not a struct
continue;
}
// "enum" or "struct" not specified so assume match
else
return &(*type); return &(*type);
} }
} }

View File

@ -109,10 +109,22 @@ public:
const std::string& name() const; 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 { bool isEnumType() const {
return classDef && classDef->str() == "enum"; return classDef && classDef->str() == "enum";
} }
bool isStructType() const {
return classDef && classDef->str() == "struct";
}
const Token *initBaseInfo(const Token *tok, const Token *tok1); const Token *initBaseInfo(const Token *tok, const Token *tok1);
const Function* getFunction(const std::string& funcName) const; const Function* getFunction(const std::string& funcName) const;

View File

@ -183,6 +183,9 @@ private:
TEST_CASE(functionArgs3); TEST_CASE(functionArgs3);
TEST_CASE(functionArgs4); TEST_CASE(functionArgs4);
TEST_CASE(functionArgs5); // #7650 TEST_CASE(functionArgs5); // #7650
TEST_CASE(functionArgs6); // #7651
TEST_CASE(functionArgs7); // #7652
TEST_CASE(functionArgs8); // #7653
TEST_CASE(namespaces1); TEST_CASE(namespaces1);
TEST_CASE(namespaces2); TEST_CASE(namespaces2);
@ -1591,7 +1594,139 @@ private:
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
if (func->argumentList.size() == 1 && func->argumentList.front().type()) { if (func->argumentList.size() == 1 && func->argumentList.front().type()) {
const Type * type = 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());
} }
} }
} }