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 <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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue