Fixed #6422 (symbol database: put function flags into a single flag variable)

This commit is contained in:
Robert Reif 2015-01-08 05:45:31 +01:00 committed by Daniel Marjamäki
parent 2b018db25a
commit ba1c24ee65
13 changed files with 328 additions and 154 deletions

View File

@ -53,7 +53,7 @@ void Check64BitPortability::pointerassignment()
const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
if (scope->function == 0 || !scope->function->hasBody) // We only look for functions with a body
if (scope->function == 0 || !scope->function->hasBody()) // We only look for functions with a body
continue;
bool retPointer = false;

View File

@ -47,7 +47,7 @@ void CheckAssert::assertWithSideEffects()
if (tmp->type() == Token::eFunction) {
const Function* f = tmp->function();
if (f->nestedIn->isClassOrStruct() && !f->isStatic && !f->isConst)
if (f->nestedIn->isClassOrStruct() && !f->isStatic() && !f->isConst())
sideEffectInAssertError(tmp, f->name()); // Non-const member function called
else {
const Scope* scope = f->functionScope;

View File

@ -367,7 +367,7 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &ftok, unsigned int
else if (arrayInfo.num().size() == 1) {
const Function* const func = ftok.function();
if (func && func->hasBody) {
if (func && func->hasBody()) {
// Get corresponding parameter..
const Variable* const parameter = func->getArgumentVar(par-1);

View File

@ -56,7 +56,7 @@ namespace {
inline bool isPureWithoutBody(Function const & func)
{
return func.isPure && !func.hasBody;
return func.isPure() && !func.hasBody();
}
}
@ -120,8 +120,8 @@ void CheckClass::constructors()
std::vector<Usage> usage(scope->varlist.size());
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
if (!func->hasBody || !(func->isConstructor() ||
func->type == Function::eOperatorEqual))
if (!func->hasBody() || !(func->isConstructor() ||
func->type == Function::eOperatorEqual))
continue;
// Mark all variables not used
@ -143,7 +143,7 @@ void CheckClass::constructors()
if (usage[count].assign || usage[count].init || var->isStatic())
continue;
if (var->isConst() && func->isOperator) // We can't set const members in assignment operator
if (var->isConst() && func->isOperator()) // We can't set const members in assignment operator
continue;
// Check if this is a class constructor
@ -456,7 +456,7 @@ void CheckClass::initializeVarList(const Function &func, std::list<const Functio
}
// member function has implementation
if (member->hasBody) {
if (member->hasBody()) {
// initialize variable use list using member function
callstack.push_back(member);
initializeVarList(*member, callstack, scope, usage);
@ -584,7 +584,7 @@ void CheckClass::initializeVarList(const Function &func, std::list<const Functio
}
// member function has implementation
if (member->hasBody) {
if (member->hasBody()) {
// initialize variable use list using member function
callstack.push_back(member);
initializeVarList(*member, callstack, scope, usage);
@ -626,7 +626,7 @@ void CheckClass::initializeVarList(const Function &func, std::list<const Functio
}
// member function has implementation
if (member->hasBody) {
if (member->hasBody()) {
// initialize variable use list using member function
callstack.push_back(member);
initializeVarList(*member, callstack, scope, usage);
@ -864,7 +864,7 @@ void CheckClass::privateFunctions()
std::list<const Function*> privateFuncs;
for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
// Get private functions..
if (func->type == Function::eFunction && func->access == Private && !func->isOperator) // TODO: There are smarter ways to check private operator usage
if (func->type == Function::eFunction && func->access == Private && !func->isOperator()) // TODO: There are smarter ways to check private operator usage
privateFuncs.push_back(&*func);
}
@ -1019,7 +1019,7 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco
std::list<Function>::const_iterator func;
for (func = type->functionList.begin(); func != type->functionList.end(); ++func) {
if (func->isVirtual) {
if (func->isVirtual()) {
if (allocation)
mallocOnClassError(tok, tok->str(), type->classDef, "virtual method");
else
@ -1119,7 +1119,7 @@ void CheckClass::operatorEq()
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
if (func->type == Function::eOperatorEqual && func->access == Public) {
// skip "deleted" functions - cannot be called anyway
if (func->isDelete)
if (func->isDelete())
continue;
// use definition for check so we don't have to deal with qualification
if (!(Token::Match(func->retDef, "%type% &") && func->retDef->str() == scope->className)) {
@ -1160,7 +1160,7 @@ void CheckClass::operatorEqRetRefThis()
std::list<Function>::const_iterator func;
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
if (func->type == Function::eOperatorEqual && func->hasBody) {
if (func->type == Function::eOperatorEqual && func->hasBody()) {
// make sure return signature is correct
if (Token::Match(func->retDef, "%type% &") && func->retDef->str() == scope->className) {
checkReturnPtrThis(&(*scope), &(*func), func->functionScope->classStart, func->functionScope->classEnd);
@ -1196,13 +1196,13 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co
// check if it is a member function
for (it = scope->functionList.begin(); it != scope->functionList.end(); ++it) {
// check for a regular function with the same name and a body
if (it->type == Function::eFunction && it->hasBody &&
if (it->type == Function::eFunction && it->hasBody() &&
it->token->str() == tok->next()->str()) {
// check for the proper return type
if (it->tokenDef->previous()->str() == "&" &&
it->tokenDef->strAt(-2) == scope->className) {
// make sure it's not a const function
if (!it->isConst) {
if (!it->isConst()) {
/** @todo make sure argument types match */
// avoid endless recursions
if (analyzedFunctions.find(&*it) == analyzedFunctions.end()) {
@ -1265,7 +1265,7 @@ void CheckClass::operatorEqToSelf()
std::list<Function>::const_iterator func;
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
if (func->type == Function::eOperatorEqual && func->hasBody) {
if (func->type == Function::eOperatorEqual && func->hasBody()) {
// make sure that the operator takes an object of the same type as *this, otherwise we can't detect self-assignment checks
if (func->argumentList.empty())
continue;
@ -1381,10 +1381,10 @@ void CheckClass::virtualDestructor()
if (scope->definedType->derivedFrom.empty()) {
if (_settings->inconclusive) {
const Function *destructor = scope->getDestructor();
if (destructor && !destructor->isVirtual) {
if (destructor && !destructor->isVirtual()) {
std::list<Function>::const_iterator func;
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
if (func->isVirtual) {
if (func->isVirtual()) {
inconclusive_errors.push_back(destructor);
break;
}
@ -1398,7 +1398,7 @@ void CheckClass::virtualDestructor()
const Function *destructor = scope->getDestructor();
// Check for destructor with implementation
if (!destructor || !destructor->hasBody)
if (!destructor || !destructor->hasBody())
continue;
// Empty destructor
@ -1477,7 +1477,7 @@ void CheckClass::virtualDestructor()
if (found != inconclusive_errors.end())
inconclusive_errors.erase(found);
}
} else if (!base_destructor->isVirtual) {
} else if (!base_destructor->isVirtual()) {
// TODO: This is just a temporary fix, better solution is needed.
// Skip situations where base class has base classes of its own, because
// some of the base classes might have virtual destructor.
@ -1564,7 +1564,7 @@ void CheckClass::checkConst()
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
// does the function have a body?
if (func->type == Function::eFunction && func->hasBody && !func->isFriend && !func->isStatic && !func->isVirtual) {
if (func->type == Function::eFunction && func->hasBody() && !func->isFriend() && !func->isStatic() && !func->isVirtual()) {
// get last token of return type
const Token *previous = func->tokenDef->previous();
@ -1586,7 +1586,7 @@ void CheckClass::checkConst()
if (!foundConst)
continue;
} else if (func->isOperator && Token::Match(previous, ";|{|}|public:|private:|protected:")) { // Operator without return type: conversion operator
} else if (func->isOperator() && Token::Match(previous, ";|{|}|public:|private:|protected:")) { // Operator without return type: conversion operator
const std::string& opName = func->tokenDef->str();
if (opName.compare(8, 5, "const") != 0 && opName[opName.size()-1] == '&')
continue;
@ -1621,11 +1621,11 @@ void CheckClass::checkConst()
else if (func->tokenDef->str() == "[")
functionName += "]";
if (!func->isConst || (!memberAccessed && !func->isOperator)) {
if (func->isInline)
checkConstError(func->token, classname, functionName, !memberAccessed && !func->isOperator);
if (!func->isConst() || (!memberAccessed && !func->isOperator())) {
if (func->isInline())
checkConstError(func->token, classname, functionName, !memberAccessed && !func->isOperator());
else // not inline
checkConstError2(func->token, func->tokenDef, classname, functionName, !memberAccessed && !func->isOperator);
checkConstError2(func->token, func->tokenDef, classname, functionName, !memberAccessed && !func->isOperator());
}
}
}
@ -1688,7 +1688,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const
bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) const
{
if (tok->function() && tok->function()->nestedIn == scope)
return !tok->function()->isStatic;
return !tok->function()->isStatic();
// not found in this class
if (!scope->definedType->derivedFrom.empty()) {
@ -1711,7 +1711,7 @@ bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) const
bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok) const
{
if (tok->function() && tok->function()->nestedIn == scope)
return tok->function()->isConst;
return tok->function()->isConst();
// not found in this class
if (!scope->definedType->derivedFrom.empty()) {
@ -1919,7 +1919,7 @@ void CheckClass::initializerListOrder()
// iterate through all member functions looking for constructors
for (func = info->functionList.begin(); func != info->functionList.end(); ++func) {
if ((func->isConstructor()) && func->hasBody) {
if ((func->isConstructor()) && func->hasBody()) {
// check for initializer list
const Token *tok = func->arg->link()->next();
@ -2015,7 +2015,7 @@ void CheckClass::checkPureVirtualFunctionCall()
std::map<const Function *, std::list<const Token *> > callsPureVirtualFunctionMap;
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
if (scope->function == 0 || !scope->function->hasBody ||
if (scope->function == 0 || !scope->function->hasBody() ||
!(scope->function->isConstructor() ||
scope->function->isDestructor()))
continue;
@ -2041,7 +2041,7 @@ const std::list<const Token *> & CheckClass::callsPureVirtualFunction(const Func
callsPureVirtualFunctionMap.insert(std::pair<const Function *, std::list< const Token *> >(&function, std::list<const Token *>()));
std::list<const Token *> & pureFunctionCalls = found.first->second;
if (found.second) {
if (function.hasBody) {
if (function.hasBody()) {
for (const Token *tok = function.arg->link();
tok && tok != function.functionScope->classEnd;
tok = tok->next()) {

View File

@ -429,7 +429,7 @@ void CheckCondition::oppositeInnerCondition()
if (tok->variable() &&
Token::Match(tok, "%var% . %var% (") &&
!tok->variable()->isConst() &&
!(tok->tokAt(2)->function() && tok->tokAt(2)->function()->isConst))
!(tok->tokAt(2)->function() && tok->tokAt(2)->function()->isConst()))
break;
if (Token::Match(tok->previous(), "[(,] %var% [,)]")) {
// is variable unchanged? default is false..

View File

@ -206,9 +206,9 @@ static const Token * functionThrowsRecursive(const Function * function, std::set
} else if (tok->function()) {
const Function * called = tok->function();
// check if called function has an exception specification
if (called->isThrow && called->throwArg) {
if (called->isThrow() && called->throwArg) {
return tok;
} else if (called->isNoExcept && called->noexceptArg &&
} else if (called->isNoExcept() && called->noexceptArg &&
called->noexceptArg->str() != "true") {
return tok;
} else if (functionThrowsRecursive(called, recursive)) {
@ -244,7 +244,7 @@ void CheckExceptionSafety::nothrowThrows()
continue;
// check noexcept functions
if (function->isNoExcept &&
if (function->isNoExcept() &&
(!function->noexceptArg || function->noexceptArg->str() == "true")) {
const Token *throws = functionThrows(function);
if (throws)
@ -252,7 +252,7 @@ void CheckExceptionSafety::nothrowThrows()
}
// check throw() functions
else if (function->isThrow && !function->throwArg) {
else if (function->isThrow() && !function->throwArg) {
const Token *throws = functionThrows(function);
if (throws)
nothrowThrowError(throws);
@ -288,7 +288,7 @@ void CheckExceptionSafety::unhandledExceptionSpecification()
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
// only check functions without exception epecification
if (scope->function && !scope->function->isThrow &&
if (scope->function && !scope->function->isThrow() &&
scope->className != "main" && scope->className != "wmain" &&
scope->className != "_tmain" && scope->className != "WinMain") {
for (const Token *tok = scope->function->functionScope->classStart->next();
@ -298,7 +298,7 @@ void CheckExceptionSafety::unhandledExceptionSpecification()
} else if (tok->function()) {
const Function * called = tok->function();
// check if called function has an exception specification
if (called->isThrow && called->throwArg) {
if (called->isThrow() && called->throwArg) {
unhandledExceptionSpecificationError(tok, called->tokenDef, scope->function->name());
break;
}

View File

@ -397,7 +397,7 @@ void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &calls
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Function* func, std::list<const Function*> *callstack) const
{
if (!func || !func->hasBody)
if (!func || !func->hasBody())
return No;
// Get return pointer..
@ -597,7 +597,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
// lock/unlock..
if (varid == 0) {
const Function* func = tok->function();
if (!func || !func->hasBody)
if (!func || !func->hasBody())
return 0;
Token *ftok = getcode(func->functionScope->classStart->next(), callstack, 0, alloctype, dealloctype, false, 1);
@ -2317,7 +2317,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
const bool constructor = func->isConstructor();
const bool destructor = func->isDestructor();
if (!func->hasBody) {
if (!func->hasBody()) {
if (destructor) { // implementation for destructor is not seen => assume it deallocates all variables properly
deallocInDestructor = true;
Dealloc = CheckMemoryLeak::Many;
@ -2445,7 +2445,7 @@ void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Toke
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
if ((func->type == Function::eFunction || func->type == Function::eOperatorEqual) &&
func->access == Public && func->hasBody) {
func->access == Public && func->hasBody()) {
const Token *tok2 = func->token;
while (tok2->str() != "{")
tok2 = tok2->next();

View File

@ -379,7 +379,7 @@ void CheckNullPointer::nullConstantDereference()
const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
if (scope->function == 0 || !scope->function->hasBody) // We only look for functions with a body
if (scope->function == 0 || !scope->function->hasBody()) // We only look for functions with a body
continue;
const Token *tok = scope->classStart;
@ -484,7 +484,7 @@ void CheckNullPointer::nullPointerDefaultArgument()
const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
if (scope->function == 0 || !scope->function->hasBody) // We only look for functions with a body
if (scope->function == 0 || !scope->function->hasBody()) // We only look for functions with a body
continue;
// Scan the argument list for default arguments that are pointers and

View File

@ -66,7 +66,7 @@ static bool isConstExpression(const Token *tok, const std::set<std::string> &con
if (tok->isName() && tok->next()->str() == "(") {
if (!tok->function() && !Token::Match(tok->previous(), ".|::") && constFunctions.find(tok->str()) == constFunctions.end())
return false;
else if (tok->function() && !tok->function()->isConst)
else if (tok->function() && !tok->function()->isConst())
return false;
}
if (tok->type() == Token::eIncDecOp)
@ -96,7 +96,7 @@ bool isSameExpression(const Token *tok1, const Token *tok2, const std::set<std::
if (tok1->isName() && tok1->next()->str() == "(") {
if (!tok1->function() && !Token::Match(tok1->previous(), ".|::") && constFunctions.find(tok1->str()) == constFunctions.end() && !tok1->isAttributeConst() && !tok1->isAttributePure())
return false;
else if (tok1->function() && !tok1->function()->isConst && !tok1->function()->isAttributeConst() && !tok1->function()->isAttributePure())
else if (tok1->function() && !tok1->function()->isConst() && !tok1->function()->isAttributeConst() && !tok1->function()->isAttributePure())
return false;
}
// templates/casts
@ -105,7 +105,7 @@ bool isSameExpression(const Token *tok1, const Token *tok2, const std::set<std::
// non-const template function that is not a dynamic_cast => return false
if (Token::simpleMatch(tok1->next()->link(), "> (") &&
!(tok1->function() && tok1->function()->isConst) &&
!(tok1->function() && tok1->function()->isConst()) &&
tok1->str() != "dynamic_cast")
return false;
@ -700,7 +700,7 @@ void CheckOther::checkRedundantAssignment()
}
} else if (scope->type == Scope::eSwitch) { // Avoid false positives if noreturn function is called in switch
const Function* const func = tok->function();
if (!func || !func->hasBody) {
if (!func || !func->hasBody()) {
varAssignments.clear();
memAssignments.clear();
continue;
@ -2252,7 +2252,7 @@ void CheckOther::doubleCloseDirError(const Token *tok, const std::string &varnam
namespace {
bool notconst(const Function* func)
{
return !func->isConst;
return !func->isConst();
}
void getConstFunctions(const SymbolDatabase *symbolDatabase, std::list<const Function*> &constFunctions)

View File

@ -508,7 +508,7 @@ private:
if (tok.next()->str() == ".") {
if (Token::Match(&tok, "%var% . %var% (")) {
const Function *function = tok.tokAt(2)->function();
if (function && function->isStatic)
if (function && function->isStatic())
return &tok;
}
if (use_dead_pointer(checks, &tok)) {
@ -1809,7 +1809,7 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, bool all
if (pointer && Token::Match(vartok, "%var% . %var% (")) {
const Function *function = vartok->tokAt(2)->function();
return (!function || !function->isStatic);
return (!function || !function->isStatic());
}
if (cpp && Token::Match(vartok->next(), "<<|>>")) {

View File

@ -335,7 +335,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// operator function
if (function.tokenDef->str().find("operator") == 0) {
function.isOperator = true;
function.isOperator(true);
// 'operator =' is special
if (function.tokenDef->str() == "operator=")
@ -374,7 +374,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.type = Function::eConstructor;
if (function.tokenDef->previous()->str() == "explicit")
function.isExplicit = true;
function.isExplicit(true);
}
const Token *tok1 = tok;
@ -383,19 +383,19 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) {
// virtual function
if (tok1->previous()->str() == "virtual") {
function.isVirtual = true;
function.isVirtual(true);
break;
}
// static function
else if (tok1->previous()->str() == "static") {
function.isStatic = true;
function.isStatic(true);
break;
}
// friend function
else if (tok1->previous()->str() == "friend") {
function.isFriend = true;
function.isFriend(true);
break;
}
@ -415,7 +415,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// const function
if (end->next()->str() == "const")
function.isConst = true;
function.isConst(true);
// count the number of constructors
if (function.isConstructor())
@ -439,9 +439,9 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// default or delete
else if (Token::Match(end, ") = default|delete ;")) {
if (end->strAt(2) == "default")
function.isDefault = true;
function.isDefault(true);
else
function.isDelete = true;
function.isDelete(true);
tok = end->tokAt(3);
@ -453,7 +453,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// const noexcept;
// const noexcept = 0;
else if (Token::Match(end, ") const| noexcept ;|=")) {
function.isNoExcept = true;
function.isNoExcept(true);
if (end->next()->str() == "const")
tok = end->tokAt(3);
@ -461,7 +461,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
tok = end->tokAt(2);
if (Token::Match(tok, "= %any% ;")) {
function.isPure = true;
function.isPure(true);
tok = tok->tokAt(2);
}
@ -481,10 +481,10 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
else
tok = end->tokAt(2);
function.isNoExcept = tok->strAt(1) != "false";
function.isNoExcept(tok->strAt(1) != "false");
if (Token::Match(tok->link()->next(), "= %any% ;")) {
function.isPure = true;
function.isPure(true);
tok = tok->tokAt(2);
}
@ -498,7 +498,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
else if (Token::Match(end, ") const| throw (") &&
(end->next()->str() == "const" ? Token::Match(end->linkAt(3), ") ;|=") :
Token::Match(end->linkAt(2), ") ;|="))) {
function.isThrow = true;
function.isThrow(true);
if (end->next()->str() == "const") {
if (end->strAt(4) != ")")
@ -511,7 +511,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
}
if (Token::Match(tok, "= %any% ;")) {
function.isPure = true;
function.isPure(true);
tok = tok->tokAt(2);
}
@ -520,7 +520,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// pure virtual function
else if (Token::Match(end, ") const| = %any% ;")) {
function.isPure = true;
function.isPure(true);
if (end->next()->str() == "const")
tok = end->tokAt(4);
@ -538,8 +538,8 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// inline function
else {
function.isInline = true;
function.hasBody = true;
function.isInline(true);
function.hasBody(true);
if (Token::Match(end, ") const| noexcept")) {
int arg = 2;
@ -550,7 +550,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
if (end->strAt(arg) == "(")
function.noexceptArg = end->tokAt(arg + 1);
function.isNoExcept = true;
function.isNoExcept(true);
} else if (Token::Match(end, ") const| throw (")) {
int arg = 3;
@ -560,7 +560,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
if (end->strAt(arg) != ")")
function.throwArg = end->tokAt(arg);
function.isThrow = true;
function.isThrow(true);
}
// find start of function '{'
@ -657,8 +657,10 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
else {
Function* function = addGlobalFunction(scope, tok, argStart, funcStart);
if (!function)
if (!function) {
_tokenizer->syntaxError(tok);
continue;
}
// global functions can't be const but we have tests that are
if (Token::Match(argStart->link(), ") const| noexcept")) {
@ -670,7 +672,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
if (argStart->link()->strAt(arg) == "(")
function->noexceptArg = argStart->link()->tokAt(arg + 1);
function->isNoExcept = true;
function->isNoExcept(true);
} else if (Token::Match(argStart->link(), ") const| throw (")) {
int arg = 3;
@ -680,7 +682,26 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
if (argStart->link()->strAt(arg) != ")")
function->throwArg = argStart->link()->tokAt(arg);
function->isThrow = true;
function->isThrow(true);
}
const Token *tok1 = tok->previous();
// look for end of previous statement
while (tok1 && !Token::Match(tok1, ";|}|{")) {
// static function
if (tok1->str() == "static") {
function->isStaticLocal(true);
break;
}
// extern function
else if (tok1->str() == "extern") {
function->isExtern(true);
break;
}
tok1 = tok1->previous();
}
}
@ -711,7 +732,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
if (argStart->link()->strAt(arg) == "(")
func->noexceptArg = argStart->link()->tokAt(arg + 1);
func->isNoExcept = true;
func->isNoExcept(true);
} else if (Token::Match(argStart->link(), ") const| throw (")) {
int arg = 3;
@ -721,7 +742,20 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
if (argStart->link()->strAt(arg) != ")")
func->throwArg = argStart->link()->tokAt(arg);
func->isThrow = true;
func->isThrow(true);
}
const Token *tok1 = tok->previous();
// look for end of previous statement
while (tok1 && !Token::Match(tok1, ";|}|{")) {
// extern function
if (tok1->str() == "extern") {
func->isExtern(true);
break;
}
tok1 = tok1->previous();
}
}
@ -1548,7 +1582,7 @@ Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, co
function->arg = argStart;
function->token = funcStart;
function->hasBody = true;
function->hasBody(true);
addNewFunction(&scope, &tok);
@ -1573,8 +1607,8 @@ Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok,
// save the function name location
function.tokenDef = funcStart;
function.isInline = false;
function.hasBody = false;
function.isInline(false);
function.hasBody(false);
function.type = Function::eFunction;
function.nestedIn = scope;
@ -1585,7 +1619,7 @@ Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok,
tok1 = tok1->previous();
// find the return type
while (tok1 && Token::Match(tok1->next(), "static|const"))
while (tok1 && Token::Match(tok1, "static|extern|const"))
tok1 = tok1->next();
if (tok1)
@ -1642,8 +1676,8 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
if (it2->scope) {
Function * func = findFunctionInScope(tok1, it2->scope);
if (func) {
if (!func->hasBody) {
func->hasBody = true;
if (!func->hasBody()) {
func->hasBody(true);
func->token = *tok;
func->arg = argStart;
addNewFunction(scope, tok);
@ -1699,22 +1733,22 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
if (match) {
for (std::multimap<std::string, const Function *>::iterator it = scope1->functionMap.find((*tok)->str()); it != scope1->functionMap.end() && it->first == (*tok)->str(); ++it) {
Function * func = const_cast<Function *>(it->second);
if (!func->hasBody) {
if (!func->hasBody()) {
if (Function::argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) {
if (func->type == Function::eDestructor && destructor) {
func->hasBody = true;
func->hasBody(true);
} else if (func->type != Function::eDestructor && !destructor) {
// normal function?
if ((*tok)->next()->link()) {
const bool hasConstKeyword = (*tok)->next()->link()->next()->str() == "const";
if ((func->isConst && hasConstKeyword) ||
(!func->isConst && !hasConstKeyword)) {
func->hasBody = true;
if ((func->isConst() && hasConstKeyword) ||
(!func->isConst() && !hasConstKeyword)) {
func->hasBody(true);
}
}
}
if (func->hasBody) {
if (func->hasBody()) {
func->token = *tok;
func->arg = argStart;
addNewFunction(scope, tok);
@ -2072,19 +2106,21 @@ void SymbolDatabase::printOut(const char *title) const
func->access == Protected ? "Protected" :
func->access == Private ? "Private" :
"???") << std::endl;
std::cout << " hasBody: " << (func->hasBody ? "true" : "false") << std::endl;
std::cout << " isInline: " << (func->isInline ? "true" : "false") << std::endl;
std::cout << " isConst: " << (func->isConst ? "true" : "false") << std::endl;
std::cout << " isVirtual: " << (func->isVirtual ? "true" : "false") << std::endl;
std::cout << " isPure: " << (func->isPure ? "true" : "false") << std::endl;
std::cout << " isStatic: " << (func->isStatic ? "true" : "false") << std::endl;
std::cout << " isFriend: " << (func->isFriend ? "true" : "false") << std::endl;
std::cout << " isExplicit: " << (func->isExplicit ? "true" : "false") << std::endl;
std::cout << " isDefault: " << (func->isDefault ? "true" : "false") << std::endl;
std::cout << " isDelete: " << (func->isDelete ? "true" : "false") << std::endl;
std::cout << " isNoExcept: " << (func->isNoExcept ? "true" : "false") << std::endl;
std::cout << " isThrow: " << (func->isThrow ? "true" : "false") << std::endl;
std::cout << " isOperator: " << (func->isOperator ? "true" : "false") << std::endl;
std::cout << " hasBody: " << (func->hasBody() ? "true" : "false") << std::endl;
std::cout << " isInline: " << (func->isInline() ? "true" : "false") << std::endl;
std::cout << " isConst: " << (func->isConst() ? "true" : "false") << std::endl;
std::cout << " isVirtual: " << (func->isVirtual() ? "true" : "false") << std::endl;
std::cout << " isPure: " << (func->isPure() ? "true" : "false") << std::endl;
std::cout << " isStatic: " << (func->isStatic() ? "true" : "false") << std::endl;
std::cout << " isStaticLocal: " << (func->isStaticLocal() ? "true" : "false") << std::endl;
std::cout << " isExtern: " << (func->isExtern() ? "true" : "false") << std::endl;
std::cout << " isFriend: " << (func->isFriend() ? "true" : "false") << std::endl;
std::cout << " isExplicit: " << (func->isExplicit() ? "true" : "false") << std::endl;
std::cout << " isDefault: " << (func->isDefault() ? "true" : "false") << std::endl;
std::cout << " isDelete: " << (func->isDelete() ? "true" : "false") << std::endl;
std::cout << " isNoExcept: " << (func->isNoExcept() ? "true" : "false") << std::endl;
std::cout << " isThrow: " << (func->isThrow() ? "true" : "false") << std::endl;
std::cout << " isOperator: " << (func->isOperator() ? "true" : "false") << std::endl;
std::cout << " isAttributeConst: " << (func->isAttributeConst() ? "true" : "false") << std::endl;
std::cout << " isAttributePure: " << (func->isAttributePure() ? "true" : "false") << std::endl;
std::cout << " isAttributeNoreturn: " << (func->isAttributeNoreturn() ? "true" : "false") << std::endl;
@ -2097,7 +2133,7 @@ void SymbolDatabase::printOut(const char *title) const
if (!func->isConstructor() && !func->isDestructor())
std::cout << " retDef: " << func->retDef->str() << " " <<_tokenizer->list.fileLine(func->retDef) << std::endl;
std::cout << " retType: " << func->retType << std::endl;
if (func->hasBody) {
if (func->hasBody()) {
std::cout << " token: " << _tokenizer->list.fileLine(func->token) << std::endl;
std::cout << " arg: " << _tokenizer->list.fileLine(func->arg) << std::endl;
}
@ -2394,7 +2430,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
nameTok = tok->previous();
endTok = nameTok->previous();
if (hasBody)
if (hasBody())
symbolDatabase->debugMessage(nameTok, "Function::addArguments found argument \'" + nameTok->str() + "\' with varid 0.");
} else
endTok = startTok;
@ -2449,7 +2485,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
bool Function::isImplicitlyVirtual(bool defaultVal) const
{
if (isVirtual)
if (isVirtual())
return true;
else if (access == Private || access == Public || access == Protected) {
bool safe = true;
@ -2476,7 +2512,7 @@ bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
// check if function defined in base class
for (std::multimap<std::string, const Function *>::const_iterator it = parent->functionMap.find(tokenDef->str()); it != parent->functionMap.end() && it->first == tokenDef->str(); ++it) {
const Function * func = it->second;
if (func->isVirtual) { // Base is virtual and of same name
if (func->isVirtual()) { // Base is virtual and of same name
const Token *temp1 = func->tokenDef->previous();
const Token *temp2 = tokenDef->previous();
bool returnMatch = true;
@ -3104,7 +3140,7 @@ const Function* Scope::findFunction(const Token *tok) const
// check if this function is a member function
if (scope && scope->functionOf && scope->functionOf->isClassOrStruct()) {
// check if isConst match
if (scope->function && scope->function->isConst == func->isConst)
if (scope->function && scope->function->isConst() == func->isConst())
return func;
} else
return func;

View File

@ -557,6 +557,43 @@ private:
};
class CPPCHECKLIB Function {
/** @brief flags mask used to access specific bit. */
enum {
fHasBody = (1 << 0), /** @brief has implementation */
fIsInline = (1 << 1), /** @brief implementation in class definition */
fIsConst = (1 << 2), /** @brief is const */
fIsVirtual = (1 << 3), /** @brief is virtual */
fIsPure = (1 << 4), /** @brief is pure virtual */
fIsStatic = (1 << 5), /** @brief is static */
fIsStaticLocal = (1 << 6), /** @brief is static local */
fIsExtern = (1 << 7), /** @brief is extern */
fIsFriend = (1 << 8), /** @brief is friend */
fIsExplicit = (1 << 9), /** @brief is explicit */
fIsDefault = (1 << 10), /** @brief is default */
fIsDelete = (1 << 11), /** @brief is delete */
fIsNoExcept = (1 << 12), /** @brief is noexcept */
fIsThrow = (1 << 13), /** @brief is throw */
fIsOperator = (1 << 14) /** @brief is operator */
};
/**
* Get specified flag state.
* @param flag flag to get state of
* @return true if flag set or false in flag not set
*/
bool getFlag(int flag) const {
return bool((flags & flag) != 0);
}
/**
* Set specified flag state.
* @param flag flag to set state
* @param state new state of flag
*/
void setFlag(int flag, bool state) {
flags = state ? flags | flag : flags & ~flag;
}
public:
enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction };
@ -572,21 +609,9 @@ public:
initArgCount(0),
type(eFunction),
access(Public),
hasBody(false),
isInline(false),
isConst(false),
isVirtual(false),
isPure(false),
isStatic(false),
isFriend(false),
isExplicit(false),
isDefault(false),
isDelete(false),
isNoExcept(false),
isThrow(false),
isOperator(false),
noexceptArg(nullptr),
throwArg(nullptr) {
throwArg(nullptr),
flags(0) {
}
const std::string &name() const {
@ -638,6 +663,98 @@ public:
return tokenDef->isDeclspecNothrow();
}
bool hasBody() const {
return getFlag(fHasBody);
}
bool isInline() const {
return getFlag(fIsInline);
}
bool isConst() const {
return getFlag(fIsConst);
}
bool isVirtual() const {
return getFlag(fIsVirtual);
}
bool isPure() const {
return getFlag(fIsPure);
}
bool isStatic() const {
return getFlag(fIsStatic);
}
bool isStaticLocal() const {
return getFlag(fIsStaticLocal);
}
bool isExtern() const {
return getFlag(fIsExtern);
}
bool isFriend() const {
return getFlag(fIsFriend);
}
bool isExplicit() const {
return getFlag(fIsExplicit);
}
bool isDefault() const {
return getFlag(fIsDefault);
}
bool isDelete() const {
return getFlag(fIsDelete);
}
bool isNoExcept() const {
return getFlag(fIsNoExcept);
}
bool isThrow() const {
return getFlag(fIsThrow);
}
bool isOperator() const {
return getFlag(fIsOperator);
}
void hasBody(bool state) {
setFlag(fHasBody, state);
}
void isInline(bool state) {
setFlag(fIsInline, state);
}
void isConst(bool state) {
setFlag(fIsConst, state);
}
void isVirtual(bool state) {
setFlag(fIsVirtual, state);
}
void isPure(bool state) {
setFlag(fIsPure, state);
}
void isStatic(bool state) {
setFlag(fIsStatic, state);
}
void isStaticLocal(bool state) {
setFlag(fIsStaticLocal, state);
}
void isExtern(bool state) {
setFlag(fIsExtern, state);
}
void isFriend(bool state) {
setFlag(fIsFriend, state);
}
void isExplicit(bool state) {
setFlag(fIsExplicit, state);
}
void isDefault(bool state) {
setFlag(fIsDefault, state);
}
void isDelete(bool state) {
setFlag(fIsDelete, state);
}
void isNoExcept(bool state) {
setFlag(fIsNoExcept, state);
}
void isThrow(bool state) {
setFlag(fIsThrow, state);
}
void isOperator(bool state) {
setFlag(fIsOperator, state);
}
const Token *tokenDef; // function name token in class definition
const Token *argDef; // function argument start '(' in class definition
const Token *token; // function name token in implementation
@ -650,19 +767,6 @@ public:
unsigned int initArgCount; // number of args with default values
Type type; // constructor, destructor, ...
AccessControl access; // public/protected/private
bool hasBody; // has implementation
bool isInline; // implementation in class definition
bool isConst; // is const
bool isVirtual; // is virtual
bool isPure; // is pure virtual
bool isStatic; // is static
bool isFriend; // is friend
bool isExplicit; // is explicit
bool isDefault; // is default
bool isDelete; // is delete
bool isNoExcept; // is noexcept
bool isThrow; // is throw
bool isOperator; // is operator
const Token *noexceptArg;
const Token *throwArg;
@ -670,6 +774,8 @@ public:
private:
bool isImplicitlyVirtual_rec(const ::Type* type, bool& safe) const;
unsigned int flags;
};
class CPPCHECKLIB Scope {

View File

@ -148,6 +148,7 @@ private:
TEST_CASE(memberFunctionOfUnknownClassMacro1);
TEST_CASE(memberFunctionOfUnknownClassMacro2);
TEST_CASE(memberFunctionOfUnknownClassMacro3);
TEST_CASE(functionLinkage);
TEST_CASE(classWithFriend);
@ -764,7 +765,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->next());
ASSERT(function && function->hasBody);
ASSERT(function && function->hasBody());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn != scope);
ASSERT(function && function->retDef == tokenizer.tokens());
}
@ -788,7 +789,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && function->isInline);
ASSERT(function && function->hasBody() && function->isInline());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
ASSERT(function && function->retDef == functionToken->previous());
@ -813,7 +814,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && !function->hasBody);
ASSERT(function && !function->hasBody());
}
}
@ -835,7 +836,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && !function->isInline);
ASSERT(function && function->hasBody() && !function->isInline());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
}
}
@ -857,7 +858,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody);
ASSERT(function && function->hasBody());
}
}
@ -878,7 +879,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && function->isInline);
ASSERT(function && function->hasBody() && function->isInline());
}
}
@ -899,7 +900,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && !function->hasBody);
ASSERT(function && !function->hasBody());
}
}
@ -920,7 +921,7 @@ private:
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody && !function->isInline);
ASSERT(function && function->hasBody() && !function->isInline());
}
}
@ -977,7 +978,7 @@ private:
for (std::list<Scope>::const_iterator scope = db->scopeList.begin(); scope != db->scopeList.end(); ++scope) {
for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
ASSERT_EQUALS("Sub", func->token->str());
ASSERT_EQUALS(true, func->hasBody);
ASSERT_EQUALS(true, func->hasBody());
ASSERT_EQUALS(Function::eConstructor, func->type);
seen_something = true;
}
@ -990,13 +991,13 @@ private:
{
GET_SYMBOL_DB("class Foo { Foo(Foo f); };");
const Function* ctor = tokenizer.tokens()->tokAt(3)->function();
ASSERT(db && ctor && ctor->type == Function::eConstructor && !ctor->isExplicit);
ASSERT(db && ctor && ctor->type == Function::eConstructor && !ctor->isExplicit());
ASSERT(ctor && ctor->retDef == 0);
}
{
GET_SYMBOL_DB("class Foo { explicit Foo(Foo f); };");
const Function* ctor = tokenizer.tokens()->tokAt(4)->function();
ASSERT(db && ctor && ctor->type == Function::eConstructor && ctor->isExplicit);
ASSERT(db && ctor && ctor->type == Function::eConstructor && ctor->isExplicit());
ASSERT(ctor && ctor->retDef == 0);
}
{
@ -1027,7 +1028,7 @@ private:
const Function *foo = &scope->functionList.front();
ASSERT(foo && foo->token->str() == "foo");
ASSERT(foo && foo->hasBody);
ASSERT(foo && foo->hasBody());
}
}
@ -1046,12 +1047,12 @@ private:
const Function *foo_int = &scope->functionList.back();
ASSERT(foo && foo->token->str() == "foo");
ASSERT(foo && foo->hasBody);
ASSERT(foo && foo->hasBody());
ASSERT(foo && foo->token->strAt(2) == ")");
ASSERT(foo_int && !foo_int->token);
ASSERT(foo_int && foo_int->tokenDef->str() == "foo");
ASSERT(foo_int && !foo_int->hasBody);
ASSERT(foo_int && !foo_int->hasBody());
ASSERT(foo_int && foo_int->tokenDef->strAt(2) == "int");
ASSERT(&foo_int->argumentList.front() == db->getVariableFromVarId(1));
@ -1123,6 +1124,37 @@ private:
}
}
void functionLinkage() {
GET_SYMBOL_DB("static void f1() { }\n"
"void f2();\n"
"extern void f3();\n"
"void f4();\n"
"extern void f5() { };\n"
"void f6() { }");
ASSERT(db && errout.str() == "");
if (db) {
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f1");
ASSERT(f && f->function() && f->function()->isStaticLocal());
f = Token::findsimplematch(tokenizer.tokens(), "f2");
ASSERT(f && f->function() && !f->function()->isStaticLocal());
f = Token::findsimplematch(tokenizer.tokens(), "f3");
ASSERT(f && f->function() && f->function()->isExtern());
f = Token::findsimplematch(tokenizer.tokens(), "f4");
ASSERT(f && f->function() && !f->function()->isExtern());
f = Token::findsimplematch(tokenizer.tokens(), "f5");
ASSERT(f && f->function() && f->function()->isExtern());
f = Token::findsimplematch(tokenizer.tokens(), "f6");
ASSERT(f && f->function() && !f->function()->isExtern());
}
}
void classWithFriend() {
GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };")
// 3 scopes: Global, 3 classes
@ -1373,7 +1405,7 @@ private:
// The class has a constructor but the implementation _is not_ seen
ASSERT_EQUALS(1U, scope->functionList.size());
const Function *function = &(scope->functionList.front());
ASSERT_EQUALS(false, function->hasBody);
ASSERT_EQUALS(false, function->hasBody());
}
// based on namespaces1 but here the namespaces match
@ -1408,7 +1440,7 @@ private:
ASSERT_EQUALS(1U, scope->functionList.size());
const Function *function = &(scope->functionList.front());
ASSERT_EQUALS("X", function->tokenDef->str());
ASSERT_EQUALS(true, function->hasBody);
ASSERT_EQUALS(true, function->hasBody());
}
void namespaces3() { // #3854 - namespace with unknown macro
@ -1915,7 +1947,7 @@ private:
void symboldatabase41() { // ticket #5197 (unknown macro)
GET_SYMBOL_DB("struct X1 { MACRO1 f(int spd) MACRO2; };\n");
ASSERT(db && db->findScopeByName("X1") && db->findScopeByName("X1")->functionList.size() == 1 && !db->findScopeByName("X1")->functionList.front().hasBody);
ASSERT(db && db->findScopeByName("X1") && db->findScopeByName("X1")->functionList.size() == 1 && !db->findScopeByName("X1")->functionList.front().hasBody());
}
void symboldatabase42() { // only put variables in variable list
@ -2379,7 +2411,7 @@ private:
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(true, x->isNoExcept);
if (x) ASSERT_EQUALS(true, x->isNoExcept());
void noexceptFunction1() {
GET_SYMBOL_DB("void func1() noexcept;\n"
@ -2410,7 +2442,7 @@ private:
#define CLASS_FUNC(x, y, z) const Function *x = findFunctionByName(#x, y); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(z, x->isNoExcept);
if (x) ASSERT_EQUALS(z, x->isNoExcept());
void noexceptFunction3() {
GET_SYMBOL_DB("struct Fred {\n"
@ -2478,7 +2510,7 @@ private:
#define FUNC_THROW(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(true, x->isThrow);
if (x) ASSERT_EQUALS(true, x->isThrow());
void throwFunction1() {
GET_SYMBOL_DB("void func1() throw();\n"
@ -2498,7 +2530,7 @@ private:
#define CLASS_FUNC_THROW(x, y) const Function *x = findFunctionByName(#x, y); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(true, x->isThrow);
if (x) ASSERT_EQUALS(true, x->isThrow());
void throwFunction2() {
GET_SYMBOL_DB("struct Fred {\n"
" void func1() throw();\n"