Fixed #752 (SymbolDatabase: Does not match function if redundant keywords mismatch (C++))
This commit is contained in:
parent
6ca76ff965
commit
55b3f0bf38
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue