Fixed #7661 (False positive: Function parameter 'e' should be passed by reference.)

This commit is contained in:
Robert Reif 2016-08-13 21:25:57 +02:00 committed by Daniel Marjamäki
parent 2ed50fbf5a
commit 73e1378af8
4 changed files with 119 additions and 88 deletions

View File

@ -32,21 +32,6 @@
#include <iomanip> #include <iomanip>
#include <cctype> #include <cctype>
static const Type* findVariableTypeInBase(const Scope* scope, const Token* typeTok)
{
if (scope && scope->definedType && !scope->definedType->derivedFrom.empty()) {
for (std::size_t i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
const Type *base = scope->definedType->derivedFrom[i].type;
if (base && base->classScope) {
const Type * type = base->classScope->findType(typeTok->str());
if (type)
return type;
}
}
}
return nullptr;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
@ -3462,100 +3447,119 @@ const Enumerator * SymbolDatabase::findEnumerator(const Token * tok) const
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const const Type* SymbolDatabase::findVariableTypeInBase(const Scope* scope, const Token* typeTok) const
{ {
// check if type does not have a namespace if (scope && scope->definedType && !scope->definedType->derivedFrom.empty()) {
if (typeTok->strAt(-1) != "::" && typeTok->strAt(1) != "::") { for (std::size_t i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
const Scope *scope = start; const Type *base = scope->definedType->derivedFrom[i].type;
if (base && base->classScope) {
// check if in member function class to see if it's present in base class const Type * type = base->classScope->findType(typeTok->str());
while (scope && scope->isExecutable() && scope->type != Scope::eFunction) { if (type)
scope = scope->nestedIn; return type;
type = findVariableTypeInBase(base->classScope, typeTok);
if (scope && scope->type == Scope::eFunction && scope->functionOf) { if (type)
scope = scope->functionOf; return type;
break;
} }
} }
}
return nullptr;
}
if (scope) { //---------------------------------------------------------------------------
const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const
{
const Scope *scope = start;
// check if type does not have a namespace
if (typeTok->strAt(-1) != "::" && typeTok->strAt(1) != "::") {
while (scope) {
// look for type in this scope
const Type * type = scope->findType(typeTok->str()); const Type * type = scope->findType(typeTok->str());
if (type) if (type)
return type; return type;
type = findVariableTypeInBase(scope, typeTok); // look for type in base classes if possible
if (scope->isClassOrStruct()) {
type = findVariableTypeInBase(scope, typeTok);
if (type) if (type)
return type; return type;
}
// check if in member function class to see if it's present in class
if (scope->type == Scope::eFunction && scope->functionOf) {
const Scope *scope1 = scope->functionOf;
type = scope1->findType(typeTok->str());
if (type)
return type;
type = findVariableTypeInBase(scope1, typeTok);
if (type)
return type;
}
scope = scope->nestedIn;
} }
} }
std::list<Type>::const_iterator type; // check for a qualified name and use it when given
else if (typeTok->strAt(-1) == "::") {
// check if type is not part of qualification
if (typeTok->strAt(1) == "::")
return nullptr;
for (type = typeList.begin(); type != typeList.end(); ++type) { // find start of qualified function name
// do the names match? const Token *tok1 = typeTok;
if (type->name() != typeTok->str())
continue;
// check if type does not have a namespace while (Token::Match(tok1->tokAt(-2), "%type% ::"))
if (typeTok->strAt(-1) != "::") { tok1 = tok1->tokAt(-2);
const Scope *parent = start;
// check if in same namespace // check for global scope
while (parent) { if (tok1->strAt(-1) == "::") {
// out of line class function belongs to class scope = &scopeList.front();
if (parent->type == Scope::eFunction && parent->functionOf)
parent = parent->functionOf; scope = scope->findRecordInNestedList(tok1->str());
else if (parent != type->enclosingScope) }
parent = parent->nestedIn;
else // find start of qualification
else {
while (scope) {
if (scope->className == tok1->str())
break; break;
} else {
const Scope *scope1 = scope->findRecordInNestedList(tok1->str());
if (type->enclosingScope == parent) { if (scope1) {
// check if "enum" specified and type is enum scope = scope1;
if (typeTok->strAt(-1) == "enum") { break;
if (type->isEnumType()) } else
return &(*type); scope = scope->nestedIn;
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 // not a struct
continue;
}
// "enum" or "struct" not specified so assume match
else
return &(*type);
} }
} }
// type has a namespace if (scope) {
else if (type->enclosingScope) { // follow qualification
bool match = true; while (scope && Token::Match(tok1, "%type% ::")) {
const Scope *scope = type->enclosingScope; tok1 = tok1->tokAt(2);
const Token *typeTok2 = typeTok->tokAt(-2); const Scope * temp = scope->findRecordInNestedList(tok1->str());
do { if (!temp) {
// A::B.. // look in base classes
if (typeTok2->isName() && typeTok2->str().find(":") == std::string::npos) { const Type * type = findVariableTypeInBase(scope, tok1);
match &= bool(scope->className == typeTok2->str());
typeTok2 = typeTok2->tokAt(-2);
scope = scope->nestedIn;
} else {
// ::A..
match &= bool(scope->type == Scope::eGlobal);
break;
}
} while (match && scope && Token::Match(typeTok2, "%any% ::"));
if (match) if (type)
return &(*type); return type;
}
scope = temp;
}
if (scope && scope->definedType)
return scope->definedType;
} }
} }

View File

@ -1111,6 +1111,7 @@ private:
const Type *findTypeInNested(const Token *tok, const Scope *startScope) const; const Type *findTypeInNested(const Token *tok, const Scope *startScope) const;
const Scope *findNamespace(const Token * tok, const Scope * scope) const; const Scope *findNamespace(const Token * tok, const Scope * scope) const;
Function *findFunctionInScope(const Token *func, const Scope *ns); Function *findFunctionInScope(const Token *func, const Scope *ns);
const Type *findVariableTypeInBase(const Scope *scope, const Token *typeTok) const;
/** Whether iName is a keyword as defined in http://en.cppreference.com/w/c/keyword and http://en.cppreference.com/w/cpp/keyword*/ /** Whether iName is a keyword as defined in http://en.cppreference.com/w/c/keyword and http://en.cppreference.com/w/cpp/keyword*/
bool isReservedName(const std::string& iName) const; bool isReservedName(const std::string& iName) const;

View File

@ -4868,8 +4868,9 @@ private:
"private:\n" "private:\n"
" MyGUI::IntCoord mCoordValue;\n" " MyGUI::IntCoord mCoordValue;\n"
"};"); "};");
ASSERT_EQUALS("[test.cpp:7]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static.\n" TODO_ASSERT_EQUALS("[test.cpp:7]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static.\n"
"[test.cpp:15]: (style, inconclusive) Technically the member function 'SelectorControl::getSize' can be const.\n", errout.str()); "[test.cpp:15]: (style, inconclusive) Technically the member function 'SelectorControl::getSize' can be const.\n",
"[test.cpp:7]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static.\n", errout.str());
checkConst("struct Foo {\n" checkConst("struct Foo {\n"
" Bar b;\n" " Bar b;\n"

View File

@ -189,6 +189,7 @@ private:
TEST_CASE(functionArgs9); // #7657 TEST_CASE(functionArgs9); // #7657
TEST_CASE(functionArgs10); TEST_CASE(functionArgs10);
TEST_CASE(functionArgs11); TEST_CASE(functionArgs11);
TEST_CASE(functionArgs12); // #7661
TEST_CASE(namespaces1); TEST_CASE(namespaces1);
TEST_CASE(namespaces2); TEST_CASE(namespaces2);
@ -1805,6 +1806,30 @@ private:
} }
} }
void functionArgs12() { // #7661
GET_SYMBOL_DB("struct A {\n"
" enum E { };\n"
" int a[10];\n"
"};\n"
"struct B : public A {\n"
" void foo(B::E e) { }\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo (");
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 namespaces1() { void namespaces1() {
GET_SYMBOL_DB("namespace fred {\n" GET_SYMBOL_DB("namespace fred {\n"
" namespace barney {\n" " namespace barney {\n"