Implement initial support for Types in Symboldatabase:
- For each class/struct/union, a Type instance is added to SymbolDatabase::typeList. - A scope is no longer created for declared but not defined types Fixed name detection for classes when they are declared like this: "class ::Foo::Sub {..."
This commit is contained in:
parent
6eed6b3cf3
commit
66a3555897
|
@ -59,17 +59,13 @@ void CheckClass::constructors()
|
||||||
for (std::size_t i = 0; i < classes; ++i) {
|
for (std::size_t i = 0; i < classes; ++i) {
|
||||||
const Scope * scope = symbolDatabase->classAndStructScopes[i];
|
const Scope * scope = symbolDatabase->classAndStructScopes[i];
|
||||||
|
|
||||||
// skip forward declarations
|
|
||||||
if (scope->isForwardDeclaration())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// There are no constructors.
|
// There are no constructors.
|
||||||
if (scope->numConstructors == 0 && style) {
|
if (scope->numConstructors == 0 && style) {
|
||||||
// If there is a private variable, there should be a constructor..
|
// If there is a private variable, there should be a constructor..
|
||||||
std::list<Variable>::const_iterator var;
|
std::list<Variable>::const_iterator var;
|
||||||
for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
|
for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
|
||||||
if (var->isPrivate() && !var->isStatic() &&
|
if (var->isPrivate() && !var->isStatic() &&
|
||||||
(!var->isClass() || (var->type() && var->type()->needInitialization == Scope::True))) {
|
(!var->isClass() || (var->type() && var->type()->needInitialization == Type::True))) {
|
||||||
noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct");
|
noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -134,18 +130,18 @@ void CheckClass::constructors()
|
||||||
|
|
||||||
// Known type that doesn't need initialization or
|
// Known type that doesn't need initialization or
|
||||||
// known type that has member variables of an unknown type
|
// known type that has member variables of an unknown type
|
||||||
else if (var->type()->needInitialization != Scope::True)
|
else if (var->type()->needInitialization != Type::True)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if type can't be copied
|
// Check if type can't be copied
|
||||||
if (!var->isPointer() && var->type() && canNotCopy(var->type()))
|
if (!var->isPointer() && var->typeScope() && canNotCopy(var->typeScope()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Don't warn about unknown types in copy constructors since we
|
// Don't warn about unknown types in copy constructors since we
|
||||||
// don't know if they can be copied or not..
|
// don't know if they can be copied or not..
|
||||||
if (!var->isPointer() &&
|
if (!var->isPointer() &&
|
||||||
!(var->type() && var->type()->needInitialization != Scope::True) &&
|
!(var->type() && var->type()->needInitialization != Type::True) &&
|
||||||
(func->type == Function::eCopyConstructor || func->type == Function::eOperatorEqual)) {
|
(func->type == Function::eCopyConstructor || func->type == Function::eOperatorEqual)) {
|
||||||
bool stdtype = false;
|
bool stdtype = false;
|
||||||
for (const Token *type = var->typeStartToken(); type && type->isName(); type = type->next())
|
for (const Token *type = var->typeStartToken(); type && type->isName(); type = type->next())
|
||||||
|
@ -173,7 +169,7 @@ void CheckClass::constructors()
|
||||||
if (classNameUsed)
|
if (classNameUsed)
|
||||||
operatorEqVarError(func->token, scope->className, var->name(), inconclusive);
|
operatorEqVarError(func->token, scope->className, var->name(), inconclusive);
|
||||||
} else if (func->access != Private) {
|
} else if (func->access != Private) {
|
||||||
const Scope *varType = var->type();
|
const Scope *varType = var->typeScope();
|
||||||
if (!varType || varType->type != Scope::eUnion)
|
if (!varType || varType->type != Scope::eUnion)
|
||||||
uninitVarError(func->token, scope->className, var->name(), inconclusive);
|
uninitVarError(func->token, scope->className, var->name(), inconclusive);
|
||||||
}
|
}
|
||||||
|
@ -857,7 +853,7 @@ void CheckClass::noMemset()
|
||||||
derefs -= (int)var->dimensions().size();
|
derefs -= (int)var->dimensions().size();
|
||||||
|
|
||||||
if (derefs == 0)
|
if (derefs == 0)
|
||||||
type = var->type();
|
type = var->typeScope();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,16 +864,19 @@ void CheckClass::noMemset()
|
||||||
if (typeTok && typeTok->str() == "(")
|
if (typeTok && typeTok->str() == "(")
|
||||||
typeTok = typeTok->next();
|
typeTok = typeTok->next();
|
||||||
|
|
||||||
if (!type)
|
if (!type) {
|
||||||
type = symbolDatabase->findVariableType(&(*scope), typeTok);
|
const Type* t = symbolDatabase->findVariableType(&(*scope), typeTok);
|
||||||
|
if (t)
|
||||||
|
type = t->classScope;
|
||||||
|
}
|
||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
checkMemsetType(&(*scope), tok, type, false);
|
checkMemsetType(&(*scope), tok, type, false);
|
||||||
} else if (tok->variable() && tok->variable()->type() && Token::Match(tok, "%var% = calloc|malloc|realloc|g_malloc|g_try_malloc|g_realloc|g_try_realloc (")) {
|
} else if (tok->variable() && tok->variable()->typeScope() && Token::Match(tok, "%var% = calloc|malloc|realloc|g_malloc|g_try_malloc|g_realloc|g_try_realloc (")) {
|
||||||
checkMemsetType(&(*scope), tok->tokAt(2), tok->variable()->type(), true);
|
checkMemsetType(&(*scope), tok->tokAt(2), tok->variable()->typeScope(), true);
|
||||||
|
|
||||||
if (tok->variable()->type()->numConstructors > 0 && _settings->isEnabled("warning"))
|
if (tok->variable()->typeScope()->numConstructors > 0 && _settings->isEnabled("warning"))
|
||||||
mallocOnClassWarning(tok, tok->strAt(2), tok->variable()->type()->classDef);
|
mallocOnClassWarning(tok, tok->strAt(2), tok->variable()->typeScope()->classDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -919,8 +918,8 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco
|
||||||
memsetError(tok, tok->str(), "'std::" + tok1->strAt(2) + "'", type->classDef->str());
|
memsetError(tok, tok->str(), "'std::" + tok1->strAt(2) + "'", type->classDef->str());
|
||||||
|
|
||||||
// check for known type
|
// check for known type
|
||||||
else if (var->type())
|
else if (var->typeScope())
|
||||||
checkMemsetType(start, tok, var->type(), allocation);
|
checkMemsetType(start, tok, var->typeScope(), allocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1648,7 +1647,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
|
||||||
if (Token::simpleMatch(var->typeStartToken(), "std ::") // assume all std::*::size() and std::*::empty() are const
|
if (Token::simpleMatch(var->typeStartToken(), "std ::") // assume all std::*::size() and std::*::empty() are const
|
||||||
&& (Token::Match(end, "size|empty|cend|crend|cbegin|crbegin|max_size|length|count|capacity|get_allocator|c_str|str ( )") || Token::Match(end, "rfind|copy")))
|
&& (Token::Match(end, "size|empty|cend|crend|cbegin|crbegin|max_size|length|count|capacity|get_allocator|c_str|str ( )") || Token::Match(end, "rfind|copy")))
|
||||||
;
|
;
|
||||||
else if (!var->type() || !isConstMemberFunc(var->type(), end))
|
else if (!var->typeScope() || !isConstMemberFunc(var->typeScope(), end))
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,9 +115,9 @@ bool CheckMemoryLeak::isclass(const Token *tok, unsigned int varid) const
|
||||||
// a type that has no side effects (no constructors and no members with constructors)
|
// a type that has no side effects (no constructors and no members with constructors)
|
||||||
/** @todo false negative: check base class for side effects */
|
/** @todo false negative: check base class for side effects */
|
||||||
/** @todo false negative: check constructors for side effects */
|
/** @todo false negative: check constructors for side effects */
|
||||||
if (var && var->type() && var->type()->numConstructors == 0 &&
|
if (var && var->typeScope() && var->typeScope()->numConstructors == 0 &&
|
||||||
(var->type()->varlist.empty() || var->type()->needInitialization == Scope::True) &&
|
(var->typeScope()->varlist.empty() || var->type()->needInitialization == Type::True) &&
|
||||||
var->type()->derivedFrom.empty())
|
var->typeScope()->derivedFrom.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -2279,7 +2279,7 @@ void CheckMemoryLeakInFunction::check()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// check for known class without implementation (forward declaration)
|
// check for known class without implementation (forward declaration)
|
||||||
if (var->isPointer() && var->type() && var->type()->isForwardDeclaration())
|
if (var->isPointer() && var->type() && !var->typeScope())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned int sz = _tokenizer->sizeOfType(var->typeStartToken());
|
unsigned int sz = _tokenizer->sizeOfType(var->typeStartToken());
|
||||||
|
@ -2349,9 +2349,9 @@ void CheckMemoryLeakInClass::check()
|
||||||
}
|
}
|
||||||
|
|
||||||
// known class?
|
// known class?
|
||||||
else if (var->type()) {
|
else if (var->typeScope()) {
|
||||||
// not derived?
|
// not derived?
|
||||||
if (var->type()->derivedFrom.empty()) {
|
if (var->typeScope()->derivedFrom.empty()) {
|
||||||
if (var->isPrivate())
|
if (var->isPrivate())
|
||||||
checkPublicFunctions(&(*scope), var->nameToken());
|
checkPublicFunctions(&(*scope), var->nameToken());
|
||||||
|
|
||||||
|
|
|
@ -3083,7 +3083,7 @@ namespace {
|
||||||
return false;
|
return false;
|
||||||
std::list<const Function*>::const_iterator it = std::find_if(constFunctions.begin(),
|
std::list<const Function*>::const_iterator it = std::find_if(constFunctions.begin(),
|
||||||
constFunctions.end(),
|
constFunctions.end(),
|
||||||
FuncFilter(v ? v->type(): 0, prev));
|
FuncFilter(v ? v->typeScope(): 0, prev));
|
||||||
if (it == constFunctions.end())
|
if (it == constFunctions.end())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1059,7 +1059,7 @@ void CheckUninitVar::check()
|
||||||
void CheckUninitVar::checkScope(const Scope* scope)
|
void CheckUninitVar::checkScope(const Scope* scope)
|
||||||
{
|
{
|
||||||
for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
|
for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
|
||||||
if ((_tokenizer->isCPP() && i->type() && !i->isPointer() && i->type()->needInitialization != Scope::True) ||
|
if ((_tokenizer->isCPP() && i->type() && !i->isPointer() && i->type()->needInitialization != Type::True) ||
|
||||||
i->isStatic() || i->isExtern() || i->isConst() || i->isArray() || i->isReference())
|
i->isStatic() || i->isExtern() || i->isConst() || i->isArray() || i->isReference())
|
||||||
continue;
|
continue;
|
||||||
if (i->nameToken()->strAt(1) == "(")
|
if (i->nameToken()->strAt(1) == "(")
|
||||||
|
|
|
@ -613,7 +613,7 @@ static bool isRecordTypeWithoutSideEffects(const Scope* type)
|
||||||
// a type that has no side effects (no constructors and no members with constructors)
|
// a type that has no side effects (no constructors and no members with constructors)
|
||||||
/** @todo false negative: check constructors for side effects */
|
/** @todo false negative: check constructors for side effects */
|
||||||
if (type && type->numConstructors == 0 &&
|
if (type && type->numConstructors == 0 &&
|
||||||
(type->varlist.empty() || type->needInitialization == Scope::True)) {
|
(type->varlist.empty() || type->definedType->needInitialization == Type::True)) {
|
||||||
bool yes = true;
|
bool yes = true;
|
||||||
for (std::vector<Scope::BaseInfo>::const_iterator i = type->derivedFrom.begin(); yes && i != type->derivedFrom.end(); ++i)
|
for (std::vector<Scope::BaseInfo>::const_iterator i = type->derivedFrom.begin(); yes && i != type->derivedFrom.end(); ++i)
|
||||||
yes = isRecordTypeWithoutSideEffects(i->scope);
|
yes = isRecordTypeWithoutSideEffects(i->scope);
|
||||||
|
@ -688,7 +688,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
|
||||||
type = Variables::pointer;
|
type = Variables::pointer;
|
||||||
else if (_tokenizer->isC() ||
|
else if (_tokenizer->isC() ||
|
||||||
i->typeEndToken()->isStandardType() ||
|
i->typeEndToken()->isStandardType() ||
|
||||||
isRecordTypeWithoutSideEffects(i->type()) ||
|
isRecordTypeWithoutSideEffects(i->typeScope()) ||
|
||||||
(Token::simpleMatch(i->typeStartToken(), "std ::") &&
|
(Token::simpleMatch(i->typeStartToken(), "std ::") &&
|
||||||
i->typeStartToken()->strAt(2) != "lock_guard" &&
|
i->typeStartToken()->strAt(2) != "lock_guard" &&
|
||||||
i->typeStartToken()->strAt(2) != "unique_lock"))
|
i->typeStartToken()->strAt(2) != "unique_lock"))
|
||||||
|
@ -893,7 +893,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
|
||||||
// is it a user defined type?
|
// is it a user defined type?
|
||||||
if (!type->isStandardType()) {
|
if (!type->isStandardType()) {
|
||||||
const Variable *variable = start->variable();
|
const Variable *variable = start->variable();
|
||||||
if (!variable || !isRecordTypeWithoutSideEffects(variable->type()))
|
if (!variable || !isRecordTypeWithoutSideEffects(variable->typeScope()))
|
||||||
allocate = false;
|
allocate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,12 +134,20 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill the classAndStructTypes set..
|
// fill typeList...
|
||||||
if (new_scope->isClassOrStruct())
|
if (new_scope->isClassOrStruct() || new_scope->type == Scope::eUnion) {
|
||||||
classAndStructTypes.insert(new_scope->className);
|
Type* new_type = findType(tok->next(), scope);
|
||||||
|
if (!new_type) {
|
||||||
|
typeList.push_back(Type(new_scope->classDef, new_scope, scope));
|
||||||
|
new_type = &typeList.back();
|
||||||
|
scope->definedTypes.push_back(new_type);
|
||||||
|
} else
|
||||||
|
new_type->classScope = new_scope;
|
||||||
|
new_scope->definedType = new_type;
|
||||||
|
}
|
||||||
|
|
||||||
// make the new scope the current scope
|
// make the new scope the current scope
|
||||||
scope = &scopeList.back();
|
scope = new_scope;
|
||||||
scope->nestedIn->nestedList.push_back(scope);
|
scope->nestedIn->nestedList.push_back(scope);
|
||||||
|
|
||||||
tok = tok2;
|
tok = tok2;
|
||||||
|
@ -175,18 +183,12 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward declaration
|
// forward declaration
|
||||||
else if (Token::Match(tok, "class|struct %var% ;") &&
|
else if (Token::Match(tok, "class|struct|union %var% ;") &&
|
||||||
tok->strAt(-1) != "friend") {
|
tok->strAt(-1) != "friend") {
|
||||||
if (!findScope(tok->next(), scope)) {
|
if (!findType(tok->next(), scope)) {
|
||||||
// fill the classAndStructTypes set..
|
// fill typeList..
|
||||||
classAndStructTypes.insert(tok->next()->str());
|
typeList.push_back(Type(tok, 0, scope));
|
||||||
|
scope->definedTypes.push_back(&typeList.back());
|
||||||
scopeList.push_back(Scope(this, tok, scope));
|
|
||||||
|
|
||||||
Scope *new_scope = &scopeList.back();
|
|
||||||
|
|
||||||
// add scope
|
|
||||||
scope->nestedList.push_back(new_scope);
|
|
||||||
}
|
}
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
}
|
}
|
||||||
|
@ -226,7 +228,11 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
varNameTok = varNameTok->next();
|
varNameTok = varNameTok->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
scope->addVariable(varNameTok, tok, tok, access[scope], new_scope, scope);
|
typeList.push_back(Type(tok, new_scope, scope));
|
||||||
|
new_scope->definedType = &typeList.back();
|
||||||
|
scope->definedTypes.push_back(&typeList.back());
|
||||||
|
|
||||||
|
scope->addVariable(varNameTok, tok, tok, access[scope], new_scope->definedType, scope);
|
||||||
|
|
||||||
const Token *tok2 = tok->next();
|
const Token *tok2 = tok->next();
|
||||||
|
|
||||||
|
@ -240,7 +246,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the new scope the current scope
|
// make the new scope the current scope
|
||||||
scope = &scopeList.back();
|
scope = new_scope;
|
||||||
scope->nestedIn->nestedList.push_back(scope);
|
scope->nestedIn->nestedList.push_back(scope);
|
||||||
|
|
||||||
tok = tok2;
|
tok = tok2;
|
||||||
|
@ -259,6 +265,10 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
new_scope->classStart = tok2;
|
new_scope->classStart = tok2;
|
||||||
new_scope->classEnd = tok2->link();
|
new_scope->classEnd = tok2->link();
|
||||||
|
|
||||||
|
typeList.push_back(Type(tok, new_scope, scope));
|
||||||
|
new_scope->definedType = &typeList.back();
|
||||||
|
scope->definedTypes.push_back(&typeList.back());
|
||||||
|
|
||||||
// make sure we have valid code
|
// make sure we have valid code
|
||||||
if (!new_scope->classEnd) {
|
if (!new_scope->classEnd) {
|
||||||
scopeList.pop_back();
|
scopeList.pop_back();
|
||||||
|
@ -266,7 +276,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the new scope the current scope
|
// make the new scope the current scope
|
||||||
scope = &scopeList.back();
|
scope = new_scope;
|
||||||
scope->nestedIn->nestedList.push_back(scope);
|
scope->nestedIn->nestedList.push_back(scope);
|
||||||
|
|
||||||
tok = tok2;
|
tok = tok2;
|
||||||
|
@ -782,7 +792,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
|
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
|
||||||
scope = &(*it);
|
scope = &(*it);
|
||||||
|
|
||||||
if (scope->isClassOrStruct() && scope->needInitialization == Scope::Unknown) {
|
if (scope->isClassOrStruct() && scope->definedType->needInitialization == Type::Unknown) {
|
||||||
// check for default constructor
|
// check for default constructor
|
||||||
bool hasDefaultConstructor = false;
|
bool hasDefaultConstructor = false;
|
||||||
|
|
||||||
|
@ -808,7 +818,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
// We assume the default constructor initializes everything.
|
// We assume the default constructor initializes everything.
|
||||||
// Another check will figure out if the constructor actually initializes everything.
|
// Another check will figure out if the constructor actually initializes everything.
|
||||||
if (hasDefaultConstructor)
|
if (hasDefaultConstructor)
|
||||||
scope->needInitialization = Scope::False;
|
scope->definedType->needInitialization = Type::False;
|
||||||
|
|
||||||
// check each member variable to see if it needs initialization
|
// check each member variable to see if it needs initialization
|
||||||
else {
|
else {
|
||||||
|
@ -820,9 +830,9 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
if (var->isClass()) {
|
if (var->isClass()) {
|
||||||
if (var->type()) {
|
if (var->type()) {
|
||||||
// does this type need initialization?
|
// does this type need initialization?
|
||||||
if (var->type()->needInitialization == Scope::True)
|
if (var->typeScope()->definedType->needInitialization == Type::True)
|
||||||
needInitialization = true;
|
needInitialization = true;
|
||||||
else if (var->type()->needInitialization == Scope::Unknown)
|
else if (var->typeScope()->definedType->needInitialization == Type::Unknown)
|
||||||
unknown = true;
|
unknown = true;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
@ -831,16 +841,16 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
|
|
||||||
if (!unknown) {
|
if (!unknown) {
|
||||||
if (needInitialization)
|
if (needInitialization)
|
||||||
scope->needInitialization = Scope::True;
|
scope->definedType->needInitialization = Type::True;
|
||||||
else
|
else
|
||||||
scope->needInitialization = Scope::False;
|
scope->definedType->needInitialization = Type::False;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope->needInitialization == Scope::Unknown)
|
if (scope->definedType->needInitialization == Type::Unknown)
|
||||||
unknowns++;
|
unknowns++;
|
||||||
}
|
}
|
||||||
} else if (scope->type == Scope::eUnion && scope->needInitialization == Scope::Unknown)
|
} else if (scope->type == Scope::eUnion && scope->definedType->needInitialization == Type::Unknown)
|
||||||
scope->needInitialization = Scope::True;
|
scope->definedType->needInitialization = Type::True;
|
||||||
}
|
}
|
||||||
|
|
||||||
retry++;
|
retry++;
|
||||||
|
@ -851,7 +861,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
|
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
|
||||||
scope = &(*it);
|
scope = &(*it);
|
||||||
|
|
||||||
if (scope->isClassOrStruct() && scope->needInitialization == Scope::Unknown)
|
if (scope->isClassOrStruct() && scope->definedType->needInitialization == Type::Unknown)
|
||||||
debugMessage(scope->classDef, "SymbolDatabase::SymbolDatabase couldn't resolve all user defined types.");
|
debugMessage(scope->classDef, "SymbolDatabase::SymbolDatabase couldn't resolve all user defined types.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -901,9 +911,9 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
const Token *tok1 = tok->tokAt(2);
|
const Token *tok1 = tok->tokAt(2);
|
||||||
if (tok1 && tok1->varId() && _variableList[tok1->varId()] == 0) {
|
if (tok1 && tok1->varId() && _variableList[tok1->varId()] == 0) {
|
||||||
const Variable *var = _variableList[tok->varId()];
|
const Variable *var = _variableList[tok->varId()];
|
||||||
if (var && var->type()) {
|
if (var && var->typeScope()) {
|
||||||
// find the member variable of this variable
|
// find the member variable of this variable
|
||||||
const Variable *var1 = var->type()->getVariable(tok1->str());
|
const Variable *var1 = var->typeScope()->getVariable(tok1->str());
|
||||||
if (var1) {
|
if (var1) {
|
||||||
// add this variable to the look up table
|
// add this variable to the look up table
|
||||||
_variableList[tok1->varId()] = var1;
|
_variableList[tok1->varId()] = var1;
|
||||||
|
@ -1587,8 +1597,10 @@ void SymbolDatabase::printVariable(const Variable *var, const char *indent) cons
|
||||||
std::cout << indent << " hasDefault: " << (var->hasDefault() ? "true" : "false") << std::endl;
|
std::cout << indent << " hasDefault: " << (var->hasDefault() ? "true" : "false") << std::endl;
|
||||||
std::cout << indent << "_type: ";
|
std::cout << indent << "_type: ";
|
||||||
if (var->type()) {
|
if (var->type()) {
|
||||||
std::cout << var->type()->className << " " << var->type()->type << " "
|
std::cout << var->type()->name();
|
||||||
<< _tokenizer->list.fileLine(var->type()->classDef) << std::endl;
|
if (var->typeScope())
|
||||||
|
std::cout << " " << var->typeScope()->type;
|
||||||
|
std::cout << " " << _tokenizer->list.fileLine(var->type()->classDef) << std::endl;
|
||||||
} else
|
} else
|
||||||
std::cout << "none" << std::endl;
|
std::cout << "none" << std::endl;
|
||||||
|
|
||||||
|
@ -1768,9 +1780,9 @@ void SymbolDatabase::printOut(const char *title) const
|
||||||
|
|
||||||
std::cout << " )" << std::endl;
|
std::cout << " )" << std::endl;
|
||||||
|
|
||||||
std::cout << " needInitialization: " << (scope->needInitialization == Scope::Unknown ? "Unknown" :
|
std::cout << " needInitialization: " << (scope->definedType->needInitialization == Type::Unknown ? "Unknown" :
|
||||||
scope->needInitialization == Scope::True ? "True" :
|
scope->definedType->needInitialization == Type::True ? "True" :
|
||||||
scope->needInitialization == Scope::False ? "False" :
|
scope->definedType->needInitialization == Type::False ? "False" :
|
||||||
"Invalid") << std::endl;
|
"Invalid") << std::endl;
|
||||||
|
|
||||||
std::list<Scope::UsingInfo>::const_iterator use;
|
std::list<Scope::UsingInfo>::const_iterator use;
|
||||||
|
@ -1863,7 +1875,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
|
||||||
endTok = tok->previous();
|
endTok = tok->previous();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Scope *argType = NULL;
|
const ::Type *argType = NULL;
|
||||||
if (!typeTok->isStandardType()) {
|
if (!typeTok->isStandardType()) {
|
||||||
argType = symbolDatabase->findVariableType(scope, typeTok);
|
argType = symbolDatabase->findVariableType(scope, typeTok);
|
||||||
if (!argType) {
|
if (!argType) {
|
||||||
|
@ -1991,8 +2003,8 @@ Scope::Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_, S
|
||||||
classEnd(start_->link()),
|
classEnd(start_->link()),
|
||||||
nestedIn(nestedIn_),
|
nestedIn(nestedIn_),
|
||||||
numConstructors(0),
|
numConstructors(0),
|
||||||
needInitialization(Scope::Unknown),
|
|
||||||
type(type_),
|
type(type_),
|
||||||
|
definedType(NULL),
|
||||||
functionOf(NULL),
|
functionOf(NULL),
|
||||||
function(NULL)
|
function(NULL)
|
||||||
{
|
{
|
||||||
|
@ -2005,36 +2017,35 @@ Scope::Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_) :
|
||||||
classEnd(NULL),
|
classEnd(NULL),
|
||||||
nestedIn(nestedIn_),
|
nestedIn(nestedIn_),
|
||||||
numConstructors(0),
|
numConstructors(0),
|
||||||
needInitialization(Scope::Unknown),
|
definedType(NULL),
|
||||||
functionOf(NULL),
|
functionOf(NULL),
|
||||||
function(NULL)
|
function(NULL)
|
||||||
{
|
{
|
||||||
|
const Token *nameTok = classDef;
|
||||||
if (!classDef) {
|
if (!classDef) {
|
||||||
type = Scope::eGlobal;
|
type = Scope::eGlobal;
|
||||||
} else if (classDef->str() == "class") {
|
} else if (classDef->str() == "class") {
|
||||||
type = Scope::eClass;
|
type = Scope::eClass;
|
||||||
// skip over qualification if present
|
nameTok = nameTok->next();
|
||||||
const Token *nameTok = classDef->next();
|
|
||||||
while (nameTok && Token::Match(nameTok, "%type% ::"))
|
|
||||||
nameTok = nameTok->tokAt(2);
|
|
||||||
className = nameTok->str();
|
|
||||||
} else if (classDef->str() == "struct") {
|
} else if (classDef->str() == "struct") {
|
||||||
type = Scope::eStruct;
|
type = Scope::eStruct;
|
||||||
// anonymous and unnamed structs don't have a name
|
nameTok = nameTok->next();
|
||||||
if (classDef->next()->str() != "{")
|
|
||||||
className = classDef->next()->str();
|
|
||||||
} else if (classDef->str() == "union") {
|
} else if (classDef->str() == "union") {
|
||||||
type = Scope::eUnion;
|
type = Scope::eUnion;
|
||||||
// anonymous and unnamed unions don't have a name
|
nameTok = nameTok->next();
|
||||||
if (classDef->next()->str() != "{")
|
|
||||||
className = classDef->next()->str();
|
|
||||||
} else if (classDef->str() == "namespace") {
|
} else if (classDef->str() == "namespace") {
|
||||||
type = Scope::eNamespace;
|
type = Scope::eNamespace;
|
||||||
className = classDef->next()->str();
|
nameTok = nameTok->next();
|
||||||
} else {
|
} else {
|
||||||
type = Scope::eFunction;
|
type = Scope::eFunction;
|
||||||
className = classDef->str();
|
|
||||||
}
|
}
|
||||||
|
// skip over qualification if present
|
||||||
|
if (nameTok && nameTok->str() == "::")
|
||||||
|
nameTok = nameTok->next();
|
||||||
|
while (nameTok && Token::Match(nameTok, "%type% ::"))
|
||||||
|
nameTok = nameTok->tokAt(2);
|
||||||
|
if (nameTok && nameTok->str() != "{") // anonymous and unnamed structs/unions don't have a name
|
||||||
|
className = nameTok->str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scope::hasDefaultConstructor() const
|
bool Scope::hasDefaultConstructor() const
|
||||||
|
@ -2228,19 +2239,19 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
|
||||||
if (vartok->varId() == 0 && !vartok->isBoolean())
|
if (vartok->varId() == 0 && !vartok->isBoolean())
|
||||||
check->debugMessage(vartok, "Scope::checkVariable found variable \'" + vartok->str() + "\' with varid 0.");
|
check->debugMessage(vartok, "Scope::checkVariable found variable \'" + vartok->str() + "\' with varid 0.");
|
||||||
|
|
||||||
const Scope *scope = NULL;
|
const Type *vType = NULL;
|
||||||
|
|
||||||
if (typetok) {
|
if (typetok) {
|
||||||
scope = check->findVariableType(this, typetok);
|
vType = check->findVariableType(this, typetok);
|
||||||
if (!scope) {
|
if (!vType) {
|
||||||
// look for variable type in any using namespace in this scope or above
|
// look for variable type in any using namespace in this scope or above
|
||||||
const Scope *parent = this;
|
const Scope *parent = this;
|
||||||
while (parent) {
|
while (parent) {
|
||||||
for (std::list<Scope::UsingInfo>::const_iterator ui = parent->usingList.begin();
|
for (std::list<Scope::UsingInfo>::const_iterator ui = parent->usingList.begin();
|
||||||
ui != parent->usingList.end(); ++ui) {
|
ui != parent->usingList.end(); ++ui) {
|
||||||
if (ui->scope) {
|
if (ui->scope) {
|
||||||
scope = check->findVariableType(ui->scope, typetok);
|
vType = check->findVariableType(ui->scope, typetok);
|
||||||
if (scope)
|
if (vType)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2249,7 +2260,7 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addVariable(vartok, typestart, vartok->previous(), varaccess, scope, this);
|
addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tok;
|
return tok;
|
||||||
|
@ -2339,19 +2350,15 @@ bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
const Scope *SymbolDatabase::findVariableType(const Scope *start, const Token *type) const
|
const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const
|
||||||
{
|
{
|
||||||
std::list<Scope>::const_iterator scope;
|
std::list<Type>::const_iterator type;
|
||||||
|
|
||||||
for (scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
|
|
||||||
// skip namespaces, functions, ...
|
|
||||||
if (scope->type != Scope::eClass && scope->type != Scope::eStruct && scope->type != Scope::eUnion)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
for (type = typeList.begin(); type != typeList.end(); ++type) {
|
||||||
// do the names match?
|
// do the names match?
|
||||||
if (scope->className == type->str()) {
|
if (type->name() == typeTok->str()) {
|
||||||
// check if type does not have a namespace
|
// check if type does not have a namespace
|
||||||
if (type->previous() == NULL || type->previous()->str() != "::") {
|
if (typeTok->strAt(-1) != "::") {
|
||||||
const Scope *parent = start;
|
const Scope *parent = start;
|
||||||
|
|
||||||
// check if in same namespace
|
// check if in same namespace
|
||||||
|
@ -2359,20 +2366,20 @@ const Scope *SymbolDatabase::findVariableType(const Scope *start, const Token *t
|
||||||
// out of line class function belongs to class
|
// out of line class function belongs to class
|
||||||
if (parent->type == Scope::eFunction && parent->functionOf)
|
if (parent->type == Scope::eFunction && parent->functionOf)
|
||||||
parent = parent->functionOf;
|
parent = parent->functionOf;
|
||||||
else if (parent != scope->nestedIn)
|
else if (parent != type->enclosingScope)
|
||||||
parent = parent->nestedIn;
|
parent = parent->nestedIn;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope->nestedIn == parent)
|
if (type->enclosingScope == parent)
|
||||||
return &(*scope);
|
return &(*type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// type has a namespace
|
// type has a namespace
|
||||||
else {
|
else {
|
||||||
// FIXME check if namespace path matches supplied path
|
// FIXME check if namespace path matches supplied path
|
||||||
return &(*scope);
|
return &(*type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2481,8 +2488,8 @@ const Function* SymbolDatabase::findFunction(const Token *tok) const
|
||||||
|
|
||||||
if (tok1->varId()) {
|
if (tok1->varId()) {
|
||||||
const Variable *var = getVariableFromVarId(tok1->varId());
|
const Variable *var = getVariableFromVarId(tok1->varId());
|
||||||
if (var && var->type())
|
if (var && var->typeScope())
|
||||||
return var->type()->findFunction(tok);
|
return var->typeScope()->findFunction(tok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2538,6 +2545,19 @@ const Scope *Scope::findRecordInNestedList(const std::string & name) const
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const Type* Scope::findType(const std::string & name) const
|
||||||
|
{
|
||||||
|
std::list<Type*>::const_iterator it;
|
||||||
|
|
||||||
|
for (it = definedTypes.begin(); it != definedTypes.end(); ++it) {
|
||||||
|
if ((*it)->name() == name)
|
||||||
|
return (*it);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
Scope *Scope::findInNestedListRecursive(const std::string & name)
|
Scope *Scope::findInNestedListRecursive(const std::string & name)
|
||||||
{
|
{
|
||||||
std::list<Scope *>::iterator it;
|
std::list<Scope *>::iterator it;
|
||||||
|
@ -2616,45 +2636,52 @@ bool SymbolDatabase::isCPP() const
|
||||||
|
|
||||||
const Scope *SymbolDatabase::findScope(const Token *tok, const Scope *startScope) const
|
const Scope *SymbolDatabase::findScope(const Token *tok, const Scope *startScope) const
|
||||||
{
|
{
|
||||||
|
const Scope *scope = 0;
|
||||||
// absolute path
|
// absolute path
|
||||||
if (tok->str() == "::") {
|
if (tok->str() == "::") {
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
const Scope *scope = &scopeList.front();
|
scope = &scopeList.front();
|
||||||
|
|
||||||
while (scope && tok && tok->isName()) {
|
|
||||||
scope = scope->findRecordInNestedList(tok->str());
|
|
||||||
|
|
||||||
if (scope) {
|
|
||||||
if (tok->strAt(1) == "::")
|
|
||||||
tok = tok->tokAt(2);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// relative path
|
// relative path
|
||||||
else if (tok->isName()) {
|
else if (tok->isName()) {
|
||||||
const Scope *scope = startScope;
|
scope = startScope;
|
||||||
|
|
||||||
while (scope && tok && tok->isName()) {
|
|
||||||
scope = scope->findRecordInNestedList(tok->str());
|
|
||||||
|
|
||||||
if (scope) {
|
|
||||||
if (tok->strAt(1) == "::")
|
|
||||||
tok = tok->tokAt(2);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (scope && tok && tok->isName()) {
|
||||||
|
if (tok->strAt(1) == "::") {
|
||||||
|
scope = scope->findRecordInNestedList(tok->str());
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
} else
|
||||||
|
return scope->findRecordInNestedList(tok->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// not a valid path
|
// not a valid path
|
||||||
else
|
return 0;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
const Type *SymbolDatabase::findType(const Token *tok, const Scope *startScope) const
|
||||||
|
{
|
||||||
|
const Scope *scope = 0;
|
||||||
|
// absolute path
|
||||||
|
if (tok->str() == "::") {
|
||||||
|
tok = tok->next();
|
||||||
|
scope = &scopeList.front();
|
||||||
|
}
|
||||||
|
// relative path
|
||||||
|
else if (tok->isName()) {
|
||||||
|
scope = startScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (scope && tok && tok->isName()) {
|
||||||
|
if (tok->strAt(1) == "::") {
|
||||||
|
scope = scope->findRecordInNestedList(tok->str());
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
} else
|
||||||
|
return scope->findType(tok->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// not a valid path
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,29 @@ struct Dimension {
|
||||||
bool known; // Known size
|
bool known; // Known size
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief Information about a class type. */
|
||||||
|
class CPPCHECKLIB Type {
|
||||||
|
public:
|
||||||
|
const Token* classDef; // Points to "class" token
|
||||||
|
const Scope* classScope;
|
||||||
|
const Scope* enclosingScope;
|
||||||
|
enum NeedInitialization {
|
||||||
|
Unknown, True, False
|
||||||
|
} needInitialization;
|
||||||
|
|
||||||
|
Type(const Token* classDef_ = 0, const Scope* classScope_ = 0, const Scope* enclosingScope_ = 0) :
|
||||||
|
classDef(classDef_),
|
||||||
|
classScope(classScope_),
|
||||||
|
enclosingScope(enclosingScope_),
|
||||||
|
needInitialization(Unknown) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& name() const {
|
||||||
|
static const std::string empty;
|
||||||
|
return classDef->next()->isName() ? classDef->strAt(1) : empty;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** @brief Information about a member variable. */
|
/** @brief Information about a member variable. */
|
||||||
class CPPCHECKLIB Variable {
|
class CPPCHECKLIB Variable {
|
||||||
/** @brief flags mask used to access specific bit. */
|
/** @brief flags mask used to access specific bit. */
|
||||||
|
@ -97,7 +120,7 @@ class CPPCHECKLIB Variable {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Variable(const Token *name_, const Token *start_, const Token *end_,
|
Variable(const Token *name_, const Token *start_, const Token *end_,
|
||||||
std::size_t index_, AccessControl access_, const Scope *type_,
|
std::size_t index_, AccessControl access_, const Type *type_,
|
||||||
const Scope *scope_)
|
const Scope *scope_)
|
||||||
: _name(name_),
|
: _name(name_),
|
||||||
_start(start_),
|
_start(start_),
|
||||||
|
@ -305,13 +328,21 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Scope pointer of known type.
|
* Get Type pointer of known type.
|
||||||
* @return pointer to type if known, NULL if not known
|
* @return pointer to type if known, NULL if not known
|
||||||
*/
|
*/
|
||||||
const Scope *type() const {
|
const Type *type() const {
|
||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Scope pointer of known type.
|
||||||
|
* @return pointer to type scope if known, NULL if not known
|
||||||
|
*/
|
||||||
|
const Scope *typeScope() const {
|
||||||
|
return _type ? _type->classScope : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Scope pointer of enclosing scope.
|
* Get Scope pointer of enclosing scope.
|
||||||
* @return pointer to enclosing scope
|
* @return pointer to enclosing scope
|
||||||
|
@ -356,7 +387,7 @@ private:
|
||||||
int _flags;
|
int _flags;
|
||||||
|
|
||||||
/** @brief pointer to user defined type info (for known types) */
|
/** @brief pointer to user defined type info (for known types) */
|
||||||
const Scope *_type;
|
const Type *_type;
|
||||||
|
|
||||||
/** @brief pointer to scope this variable is in */
|
/** @brief pointer to scope this variable is in */
|
||||||
const Scope *_scope;
|
const Scope *_scope;
|
||||||
|
@ -468,7 +499,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ScopeType { eGlobal, eClass, eStruct, eUnion, eNamespace, eFunction, eIf, eElse, eElseIf, eFor, eWhile, eDo, eSwitch, eUnconditional, eTry, eCatch };
|
enum ScopeType { eGlobal, eClass, eStruct, eUnion, eNamespace, eFunction, eIf, eElse, eElseIf, eFor, eWhile, eDo, eSwitch, eUnconditional, eTry, eCatch };
|
||||||
enum NeedInitialization { Unknown, True, False };
|
|
||||||
|
|
||||||
Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_);
|
Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_);
|
||||||
Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_, ScopeType type_, const Token *start_);
|
Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_, ScopeType type_, const Token *start_);
|
||||||
|
@ -486,8 +516,9 @@ public:
|
||||||
std::list<Scope *> nestedList;
|
std::list<Scope *> nestedList;
|
||||||
unsigned int numConstructors;
|
unsigned int numConstructors;
|
||||||
std::list<UsingInfo> usingList;
|
std::list<UsingInfo> usingList;
|
||||||
NeedInitialization needInitialization;
|
|
||||||
ScopeType type;
|
ScopeType type;
|
||||||
|
Type* definedType;
|
||||||
|
std::list<Type*> definedTypes;
|
||||||
|
|
||||||
// function specific fields
|
// function specific fields
|
||||||
Scope *functionOf; // scope this function belongs to
|
Scope *functionOf; // scope this function belongs to
|
||||||
|
@ -508,10 +539,6 @@ public:
|
||||||
type == eTry || type == eCatch);
|
type == eTry || type == eCatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isForwardDeclaration() const {
|
|
||||||
return isClassOrStruct() && classStart == NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief find a function
|
* @brief find a function
|
||||||
* @param tok token of function call
|
* @param tok token of function call
|
||||||
|
@ -530,6 +557,8 @@ public:
|
||||||
return const_cast<Scope *>(static_cast<const Scope *>(this)->findRecordInNestedList(name));
|
return const_cast<Scope *>(static_cast<const Scope *>(this)->findRecordInNestedList(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Type *findType(const std::string & name) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief find if name is in nested list
|
* @brief find if name is in nested list
|
||||||
* @param name name of nested scope
|
* @param name name of nested scope
|
||||||
|
@ -539,7 +568,7 @@ public:
|
||||||
const Scope *findQualifiedScope(const std::string & name) const;
|
const Scope *findQualifiedScope(const std::string & name) const;
|
||||||
|
|
||||||
void addVariable(const Token *token_, const Token *start_,
|
void addVariable(const Token *token_, const Token *start_,
|
||||||
const Token *end_, AccessControl access_, const Scope *type_,
|
const Token *end_, AccessControl access_, const Type *type_,
|
||||||
const Scope *scope_) {
|
const Scope *scope_) {
|
||||||
varlist.push_back(Variable(token_, start_, end_, varlist.size(),
|
varlist.push_back(Variable(token_, start_, end_, varlist.size(),
|
||||||
access_,
|
access_,
|
||||||
|
@ -604,13 +633,16 @@ public:
|
||||||
/** @brief Fast access to class and struct scopes */
|
/** @brief Fast access to class and struct scopes */
|
||||||
std::vector<const Scope *> classAndStructScopes;
|
std::vector<const Scope *> classAndStructScopes;
|
||||||
|
|
||||||
|
/** @brief Fast access to types */
|
||||||
|
std::list<Type> typeList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief find a variable type if it's a user defined type
|
* @brief find a variable type if it's a user defined type
|
||||||
* @param start scope to start looking in
|
* @param start scope to start looking in
|
||||||
* @param type token containing variable type
|
* @param type token containing variable type
|
||||||
* @return pointer to type if found or NULL if not found
|
* @return pointer to type if found or NULL if not found
|
||||||
*/
|
*/
|
||||||
const Scope *findVariableType(const Scope *start, const Token *type) const;
|
const Type *findVariableType(const Scope *start, const Token *type) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief find a function
|
* @brief find a function
|
||||||
|
@ -621,13 +653,21 @@ public:
|
||||||
|
|
||||||
const Scope *findScopeByName(const std::string& name) const;
|
const Scope *findScopeByName(const std::string& name) const;
|
||||||
|
|
||||||
|
const Type *findType(const Token *tok, const Scope *startScope) const;
|
||||||
|
Type *findType(const Token *tok, Scope *startScope) const {
|
||||||
|
return const_cast<Type *>(this->findType(tok, static_cast<const Scope *>(startScope)));
|
||||||
|
}
|
||||||
|
|
||||||
const Scope *findScope(const Token *tok, const Scope *startScope) const;
|
const Scope *findScope(const Token *tok, const Scope *startScope) const;
|
||||||
Scope *findScope(const Token *tok, Scope *startScope) const {
|
Scope *findScope(const Token *tok, Scope *startScope) const {
|
||||||
return const_cast<Scope *>(this->findScope(tok, static_cast<const Scope *>(startScope)));
|
return const_cast<Scope *>(this->findScope(tok, static_cast<const Scope *>(startScope)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isClassOrStruct(const std::string &type) const {
|
bool isClassOrStruct(const std::string &type) const {
|
||||||
return bool(classAndStructTypes.find(type) != classAndStructTypes.end());
|
for (std::list<Type>::const_iterator i = typeList.begin(); i != typeList.end(); ++i)
|
||||||
|
if (i->name() == type)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Variable *getVariableFromVarId(std::size_t varId) const {
|
const Variable *getVariableFromVarId(std::size_t varId) const {
|
||||||
|
@ -659,9 +699,6 @@ private:
|
||||||
void addNewFunction(Scope **info, const Token **tok);
|
void addNewFunction(Scope **info, const Token **tok);
|
||||||
static bool isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart);
|
static bool isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart);
|
||||||
|
|
||||||
/** class/struct types */
|
|
||||||
std::set<std::string> classAndStructTypes;
|
|
||||||
|
|
||||||
const Tokenizer *_tokenizer;
|
const Tokenizer *_tokenizer;
|
||||||
const Settings *_settings;
|
const Settings *_settings;
|
||||||
ErrorLogger *_errorLogger;
|
ErrorLogger *_errorLogger;
|
||||||
|
|
|
@ -1783,9 +1783,9 @@ private:
|
||||||
"class Bar;\n"
|
"class Bar;\n"
|
||||||
"class Sub;\n");
|
"class Sub;\n");
|
||||||
|
|
||||||
ASSERT_EQUALS("[test.cpp:20]: (warning) Member variable 'Sub::f' is not initialized in the constructor.\n"
|
ASSERT_EQUALS("[test.cpp:9]: (warning) Member variable 'Sub::b' is not initialized in the constructor.\n"
|
||||||
"[test.cpp:9]: (warning) Member variable 'Sub::b' is not initialized in the constructor.\n"
|
"[test.cpp:12]: (warning) Member variable 'Sub::b' is not initialized in the constructor.\n"
|
||||||
"[test.cpp:12]: (warning) Member variable 'Sub::b' is not initialized in the constructor.\n", errout.str());
|
"[test.cpp:20]: (warning) Member variable 'Sub::f' is not initialized in the constructor.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninitVarArray1() {
|
void uninitVarArray1() {
|
||||||
|
|
|
@ -187,6 +187,7 @@ private:
|
||||||
TEST_CASE(symboldatabase28);
|
TEST_CASE(symboldatabase28);
|
||||||
TEST_CASE(symboldatabase29); // ticket #4442 (segmentation fault)
|
TEST_CASE(symboldatabase29); // ticket #4442 (segmentation fault)
|
||||||
TEST_CASE(symboldatabase30);
|
TEST_CASE(symboldatabase30);
|
||||||
|
TEST_CASE(symboldatabase31);
|
||||||
|
|
||||||
TEST_CASE(isImplicitlyVirtual);
|
TEST_CASE(isImplicitlyVirtual);
|
||||||
|
|
||||||
|
@ -1371,7 +1372,7 @@ private:
|
||||||
void symboldatabase28() {
|
void symboldatabase28() {
|
||||||
GET_SYMBOL_DB("struct S {};\n"
|
GET_SYMBOL_DB("struct S {};\n"
|
||||||
"void foo(struct S s) {}");
|
"void foo(struct S s) {}");
|
||||||
ASSERT(db && db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->type() && db->getVariableFromVarId(1)->type()->className == "S");
|
ASSERT(db && db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->typeScope() && db->getVariableFromVarId(1)->typeScope()->className == "S");
|
||||||
}
|
}
|
||||||
|
|
||||||
// #ticket #4442 (segmentation fault)
|
// #ticket #4442 (segmentation fault)
|
||||||
|
@ -1388,6 +1389,51 @@ private:
|
||||||
ASSERT(db && db->functionScopes.size() == 1 && db->functionScopes[0]->functionOf);
|
ASSERT(db && db->functionScopes.size() == 1 && db->functionScopes[0]->functionOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void symboldatabase31() {
|
||||||
|
GET_SYMBOL_DB("class Foo;\n"
|
||||||
|
"class Bar;\n"
|
||||||
|
"class Sub;\n"
|
||||||
|
"class Foo { class Sub; };\n"
|
||||||
|
"class Bar { class Sub; };\n"
|
||||||
|
"class Bar::Sub {\n"
|
||||||
|
" int b;\n"
|
||||||
|
"public:\n"
|
||||||
|
" Sub() { }\n"
|
||||||
|
" Sub(int);\n"
|
||||||
|
"};\n"
|
||||||
|
"Bar::Sub::Sub(int) { };\n"
|
||||||
|
"class ::Foo::Sub {\n"
|
||||||
|
" int f;\n"
|
||||||
|
"public:\n"
|
||||||
|
" ~Sub();\n"
|
||||||
|
" Sub();\n"
|
||||||
|
"};\n"
|
||||||
|
"::Foo::Sub::~Sub() { }\n"
|
||||||
|
"::Foo::Sub::Sub() { }\n"
|
||||||
|
"class Foo;\n"
|
||||||
|
"class Bar;\n"
|
||||||
|
"class Sub;\n");
|
||||||
|
ASSERT(db && db->typeList.size() == 5);
|
||||||
|
ASSERT(db && db->isClassOrStruct("Foo"));
|
||||||
|
ASSERT(db && db->isClassOrStruct("Bar"));
|
||||||
|
ASSERT(db && db->isClassOrStruct("Sub"));
|
||||||
|
if (!db || db->typeList.size() < 5)
|
||||||
|
return;
|
||||||
|
std::list<Type>::const_iterator i = db->typeList.begin();
|
||||||
|
const Type* Foo = &(*i++);
|
||||||
|
const Type* Bar = &(*i++);
|
||||||
|
const Type* Sub = &(*i++);
|
||||||
|
const Type* Foo_Sub = &(*i++);
|
||||||
|
const Type* Bar_Sub = &(*i);
|
||||||
|
ASSERT(Foo && Foo->classDef && Foo->classScope && Foo->enclosingScope && Foo->name() == "Foo");
|
||||||
|
ASSERT(Bar && Bar->classDef && Bar->classScope && Bar->enclosingScope && Bar->name() == "Bar");
|
||||||
|
ASSERT(Sub && Sub->classDef && !Sub->classScope && Sub->enclosingScope && Sub->name() == "Sub");
|
||||||
|
ASSERT(Foo_Sub && Foo_Sub->classDef && Foo_Sub->classScope && Foo_Sub->enclosingScope == Foo->classScope && Foo_Sub->name() == "Sub");
|
||||||
|
ASSERT(Bar_Sub && Bar_Sub->classDef && Bar_Sub->classScope && Bar_Sub->enclosingScope == Bar->classScope && Bar_Sub->name() == "Sub");
|
||||||
|
ASSERT(Foo_Sub && Foo_Sub->classScope && Foo_Sub->classScope->numConstructors == 1 && Foo_Sub->classScope->className == "Sub");
|
||||||
|
ASSERT(Bar_Sub && Bar_Sub->classScope && Bar_Sub->classScope->numConstructors == 2 && Bar_Sub->classScope->className == "Sub");
|
||||||
|
}
|
||||||
|
|
||||||
void isImplicitlyVirtual() {
|
void isImplicitlyVirtual() {
|
||||||
{
|
{
|
||||||
GET_SYMBOL_DB("class Base {\n"
|
GET_SYMBOL_DB("class Base {\n"
|
||||||
|
|
Loading…
Reference in New Issue