Fixed #7661 (False positive: Function parameter 'e' should be passed by reference.)
This commit is contained in:
parent
2ed50fbf5a
commit
73e1378af8
|
@ -32,21 +32,6 @@
|
|||
#include <iomanip>
|
||||
#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)
|
||||
|
@ -3462,100 +3447,119 @@ const Enumerator * SymbolDatabase::findEnumerator(const Token * tok) const
|
|||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const Type* SymbolDatabase::findVariableTypeInBase(const Scope* scope, const Token* typeTok) const
|
||||
{
|
||||
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;
|
||||
type = findVariableTypeInBase(base->classScope, typeTok);
|
||||
if (type)
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const
|
||||
{
|
||||
// check if type does not have a namespace
|
||||
if (typeTok->strAt(-1) != "::" && typeTok->strAt(1) != "::") {
|
||||
const Scope *scope = start;
|
||||
|
||||
// check if in member function class to see if it's present in base class
|
||||
while (scope && scope->isExecutable() && scope->type != Scope::eFunction) {
|
||||
scope = scope->nestedIn;
|
||||
|
||||
if (scope && scope->type == Scope::eFunction && scope->functionOf) {
|
||||
scope = scope->functionOf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
// 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());
|
||||
|
||||
if (type)
|
||||
return type;
|
||||
|
||||
// look for type in base classes if possible
|
||||
if (scope->isClassOrStruct()) {
|
||||
type = findVariableTypeInBase(scope, typeTok);
|
||||
|
||||
if (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;
|
||||
}
|
||||
|
||||
std::list<Type>::const_iterator type;
|
||||
|
||||
for (type = typeList.begin(); type != typeList.end(); ++type) {
|
||||
// do the names match?
|
||||
if (type->name() != typeTok->str())
|
||||
continue;
|
||||
|
||||
// check if type does not have a namespace
|
||||
if (typeTok->strAt(-1) != "::") {
|
||||
const Scope *parent = start;
|
||||
|
||||
// check if in same namespace
|
||||
while (parent) {
|
||||
// out of line class function belongs to class
|
||||
if (parent->type == Scope::eFunction && parent->functionOf)
|
||||
parent = parent->functionOf;
|
||||
else if (parent != type->enclosingScope)
|
||||
parent = parent->nestedIn;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (type->enclosingScope == parent) {
|
||||
// check if "enum" specified and type is enum
|
||||
if (typeTok->strAt(-1) == "enum") {
|
||||
if (type->isEnumType())
|
||||
return &(*type);
|
||||
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
|
||||
else if (type->enclosingScope) {
|
||||
bool match = true;
|
||||
const Scope *scope = type->enclosingScope;
|
||||
const Token *typeTok2 = typeTok->tokAt(-2);
|
||||
do {
|
||||
// A::B..
|
||||
if (typeTok2->isName() && typeTok2->str().find(":") == std::string::npos) {
|
||||
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)
|
||||
return &(*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;
|
||||
|
||||
// find start of qualified function name
|
||||
const Token *tok1 = typeTok;
|
||||
|
||||
while (Token::Match(tok1->tokAt(-2), "%type% ::"))
|
||||
tok1 = tok1->tokAt(-2);
|
||||
|
||||
// check for global scope
|
||||
if (tok1->strAt(-1) == "::") {
|
||||
scope = &scopeList.front();
|
||||
|
||||
scope = scope->findRecordInNestedList(tok1->str());
|
||||
}
|
||||
|
||||
// find start of qualification
|
||||
else {
|
||||
while (scope) {
|
||||
if (scope->className == tok1->str())
|
||||
break;
|
||||
else {
|
||||
const Scope *scope1 = scope->findRecordInNestedList(tok1->str());
|
||||
|
||||
if (scope1) {
|
||||
scope = scope1;
|
||||
break;
|
||||
} else
|
||||
scope = scope->nestedIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
// follow qualification
|
||||
while (scope && Token::Match(tok1, "%type% ::")) {
|
||||
tok1 = tok1->tokAt(2);
|
||||
const Scope * temp = scope->findRecordInNestedList(tok1->str());
|
||||
if (!temp) {
|
||||
// look in base classes
|
||||
const Type * type = findVariableTypeInBase(scope, tok1);
|
||||
|
||||
if (type)
|
||||
return type;
|
||||
}
|
||||
scope = temp;
|
||||
}
|
||||
|
||||
if (scope && scope->definedType)
|
||||
return scope->definedType;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1111,6 +1111,7 @@ private:
|
|||
const Type *findTypeInNested(const Token *tok, const Scope *startScope) const;
|
||||
const Scope *findNamespace(const Token * tok, const Scope * scope) const;
|
||||
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*/
|
||||
bool isReservedName(const std::string& iName) const;
|
||||
|
|
|
@ -4868,8 +4868,9 @@ private:
|
|||
"private:\n"
|
||||
" MyGUI::IntCoord mCoordValue;\n"
|
||||
"};");
|
||||
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());
|
||||
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",
|
||||
"[test.cpp:7]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static.\n", errout.str());
|
||||
|
||||
checkConst("struct Foo {\n"
|
||||
" Bar b;\n"
|
||||
|
|
|
@ -189,6 +189,7 @@ private:
|
|||
TEST_CASE(functionArgs9); // #7657
|
||||
TEST_CASE(functionArgs10);
|
||||
TEST_CASE(functionArgs11);
|
||||
TEST_CASE(functionArgs12); // #7661
|
||||
|
||||
TEST_CASE(namespaces1);
|
||||
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() {
|
||||
GET_SYMBOL_DB("namespace fred {\n"
|
||||
" namespace barney {\n"
|
||||
|
|
Loading…
Reference in New Issue