67 switch (valueType->
type) {
68 case ValueType::Type::UNKNOWN_TYPE:
69 case ValueType::Type::NONSTD:
72 case ValueType::Type::RECORD:
77 case ValueType::Type::POD:
78 case ValueType::Type::SMART_POINTER:
79 case ValueType::Type::CONTAINER:
80 case ValueType::Type::ITERATOR:
81 case ValueType::Type::VOID:
82 case ValueType::Type::BOOL:
83 case ValueType::Type::CHAR:
84 case ValueType::Type::SHORT:
85 case ValueType::Type::WCHAR_T:
86 case ValueType::Type::INT:
87 case ValueType::Type::LONG:
88 case ValueType::Type::LONGLONG:
89 case ValueType::Type::UNKNOWN_INT:
90 case ValueType::Type::FLOAT:
91 case ValueType::Type::DOUBLE:
92 case ValueType::Type::LONGDOUBLE:
149 const std::map<nonneg int, VariableUsage> &
varUsage()
const {
193 if (varid1 == varid2) {
200 for (std::set<nonneg int>::const_iterator i = var1->
_aliases.cbegin(); i != var1->
_aliases.cend(); ++i) {
212 for (std::set<nonneg int>::const_iterator i = var2->
_aliases.cbegin(); i != var2->
_aliases.cend(); ++i) {
232 for (std::set<nonneg int>::const_iterator i = usage->
_aliases.cbegin(); i != usage->
_aliases.cend(); ++i) {
249 for (std::set<nonneg int>::const_iterator aliases = usage->
_aliases.cbegin(); aliases != usage->
_aliases.cend(); ++aliases)
299 aliased->
_read =
true;
319 usage->
_read =
false;
329 for (std::set<nonneg int>::const_iterator aliases = usage->
_aliases.cbegin(); aliases != usage->
_aliases.cend(); ++aliases) {
354 for (std::set<nonneg int>::const_iterator aliases = usage->
_aliases.cbegin(); aliases != usage->
_aliases.cend(); ++aliases) {
371 usage->
_read =
false;
375 for (std::set<nonneg int>::const_iterator aliases = usage->
_aliases.cbegin(); aliases != usage->
_aliases.cend(); ++aliases) {
389 const std::map<nonneg int, VariableUsage>::iterator i =
mVarUsage.find(varid);
409 const Token*
const tokOld = tok;
425 if (
Token::Match(tok,
"( const| struct|union| %type% * ) ( ("))
426 tok = tok->
link()->next();
428 if (
Token::Match(tok,
"( [(<] const| struct|union| %type% *| [>)]"))
432 (
Token::Match(tok->
next(),
"< const| struct|union| %type% *| > ( &| %name%"))) {
433 bool addressOf =
false;
439 if (tok->
str() ==
"(") {
441 if (tok->
str() ==
"const")
447 while ((tok->
isName() && tok->
varId() == 0) || (tok->
str() ==
"*") || (tok->
str() ==
")"))
450 if (tok->
str() ==
"&") {
453 }
else if (tok->
str() ==
"(") {
455 if (tok->
str() ==
"&") {
465 else if (tok->
str().find(
"cast") != std::string::npos &&
466 tok->
strAt(1) ==
"<") {
468 if (tok->
str() ==
"const")
477 if (tok->
str() ==
"*")
483 if (tok->
str() ==
"&") {
491 if (tok->
str() ==
"&") {
494 }
else if (tok->
str() ==
"new")
505 variables.
read(varid2, tok);
545 }
else if (tok->
strAt(1) ==
"?") {
549 variables.
read(varid2, tok);
551 variables.
readAll(varid2, tok);
555 variables.
alias(varid1, varid2,
true);
557 variables.
alias(varid1, varid2,
true);
562 variables.
read(varid2, tok);
569 for (
const Token *rhs = tok; rhs && rhs->
str() !=
";"; rhs = rhs->next()) {
570 if (rhs->varId() == varid1) {
571 variables.
use(varid1, tok);
603 if (rhsVarTok && rhsVarTok->
varId()) {
623 variables.
use(varid2,tok);
632 for (; tok; tok = tok->
previous()) {
633 if (tok->
str() ==
"}" || tok->
str() ==
")")
635 else if (tok->
str() ==
"(")
637 else if (tok->
str() ==
"{") {
638 return (tok->
strAt(-1) ==
"struct" || tok->
strAt(-2) ==
"struct" || tok->
strAt(-1) ==
"class" || tok->
strAt(-2) ==
"class" || tok->
strAt(-1) ==
"union" || tok->
strAt(-2) ==
"union");
652 while (tok && tok->
str() ==
"[")
653 tok = tok->
link()->next();
662 if (tok->
str() ==
"[")
663 tok = tok->
link()->next();
677 if (tok->
str() ==
",") {
696 for (std::list<Variable>::const_iterator i = scope->
varlist.cbegin(); i != scope->
varlist.cend(); ++i) {
697 if (i->isThrow() || i->isExtern())
700 if (i->isArray() && (i->nameToken()->previous()->str() ==
"*" || i->nameToken()->strAt(-2) ==
"*"))
702 else if (i->isArray() && i->nameToken()->previous()->str() ==
"&")
704 else if (i->isArray())
708 else if (i->nameToken()->previous()->str() ==
"*" && i->nameToken()->strAt(-2) ==
"*")
710 else if (i->isPointerToArray())
712 else if (i->isPointer())
715 i->typeEndToken()->isStandardType() ||
724 const Token* defValTok = i->nameToken()->
next();
725 if (
Token::Match(i->nameToken()->previous(),
"* %var% ) ("))
727 for (; defValTok; defValTok = defValTok->
next()) {
728 if (defValTok->
str() ==
"[")
729 defValTok = defValTok->
link();
730 else if (defValTok->
str() ==
"(" || defValTok->
str() ==
"{" || defValTok->
str() ==
"=" || defValTok->
str() ==
":") {
731 variables.
addVar(&*i, type,
true);
733 }
else if (defValTok->
str() ==
";" || defValTok->
str() ==
"," || defValTok->
str() ==
")") {
738 if (i->isArray() && i->isClass() &&
739 !(i->isStlType() && i->valueType() && i->valueType()->containerTypeToken && i->valueType()->containerTypeToken->isStandardType()))
740 variables.
write(i->declarationId(), i->nameToken());
741 if (i->isArray() &&
Token::Match(i->nameToken(),
"%name% [ %var% ]"))
742 variables.
read(i->nameToken()->tokAt(2)->varId(), i->nameToken());
744 if (defValTok && defValTok->
next()) {
746 if (defValTok->
str() ==
"=" && defValTok->
next()->
str() !=
"{") {
750 const Token* tokBraceStart =
nullptr;
753 tokBraceStart = defValTok->
next();
754 }
else if (defValTok->
str() ==
"{") {
756 tokBraceStart = defValTok;
759 for (
const Token* tok = tokBraceStart->
next(); tok && tok != tokBraceStart->
link(); tok = tok->next()) {
762 variables.
read(tok->varId(), i->nameToken());
777 for (; tok && tok != scope->
bodyEnd; tok = tok->
next()) {
780 return s->bodyStart == tok;
803 for (
const Token* tok2 = tok->
next(); tok2; tok2 = tok2->
next()) {
806 const Variable *var = tok2->variable();
811 if (tok2->strAt(-1) ==
">") {
812 for (
const Token *tok3 = tok; tok3 != tok2; tok3 = tok3->
next()) {
814 variables.
use(tok3->varId(), tok3);
830 variables.
readAll(rhs->varId(), rhs);
844 if (tok->
str() !=
"delete") {
846 varid = varTok->
varId();
847 tok = varTok->
next();
848 }
else if (tok->
strAt(1) ==
"[") {
850 varid = varTok->
varId();
860 variables.
use(varid, tok);
867 for (
const Token *tok2 = tok->
next(); tok2; tok2 = tok2->
next()) {
869 variables.
readAll(tok2->varId(), tok);
870 else if (tok2->str() ==
";")
876 else if (
Token::Match(tok,
"*| ++|--| %name% ++|--| %assign%") ||
877 Token::Match(tok,
"*| ( const| %type% *| ) %name% %assign%")) {
878 bool dereference =
false;
882 if (tok->
str() ==
"*") {
887 if (
Token::Match(tok,
"( const| %type% *| ) %name% %assign%"))
888 tok = tok->
link()->next();
890 else if (tok->
str() ==
"(")
902 const Token *
const start = tok;
905 bool inwhile =
false;
920 variables.
use(varid1, tok);
928 variables.
use(varid1, tok);
933 variables.
write(varid1, tok);
935 variables.
read(varid1, tok);
938 if (var && (inwhile || start->
strAt(-1) ==
",")) {
939 variables.
use(varid1, tok);
942 variables.
read(varid1, tok);
954 if (allocFuncCallToken->
str() ==
"new") {
955 const Token *type = allocFuncCallToken->
next();
960 type = type->
link()->next();
966 allocateMemory =
false;
973 variables.
write(varid1, tok);
974 }
else if (varid1 &&
Token::Match(tok,
"%varid% .", varid1)) {
975 variables.
read(varid1, tok);
976 variables.
write(varid1, start);
978 variables.
write(varid1, tok);
989 else if (tok->
varId() != varid1 &&
991 tok->
strAt(-1) !=
"&")
998 if (tok != start && equal && equal->
str() ==
"=") {
1003 variables.
read(varId,tok);
1013 const Token *eq = tok;
1019 if (tok->
str() ==
"*") {
1020 tok = tok->
tokAt(2);
1021 if (tok->
str() ==
"(")
1022 tok = tok->
link()->next();
1035 variables.
read(varid, tok);
1073 variables.
use(tok->
next()->
link()->next()->varId(), tok);
1076 while (vartok->
str() ==
"*")
1077 vartok = vartok->
next();
1080 variables.
use(vartok->
varId(), vartok);
1090 }
else if (
Token::Match(tok,
"std :: ref ( %var% )")) {
1134 for (
const Token *tok2 = tok->
next(); tok2 && tok2->
str() !=
";"; tok2 = tok2->next()) {
1135 if (tok2->varId()) {
1136 if (tok2->strAt(1) ==
"=")
1137 variables.
write(tok2->varId(), tok);
1138 else if (tok2->next() && tok2->next()->isAssignmentOp())
1139 variables.
use(tok2->varId(), tok);
1141 variables.
read(tok2->varId(), tok);
1157 logChecker(
"CheckUnusedVar::checkFunctionVariableUsage");
1162 auto reportLibraryCfgError = [
this](
const Token* tok,
const std::string& typeName) {
1166 "checkLibraryCheckType",
1167 "--check-library: Provide <type-checks><unusedvar> configuration for " + typeName);
1185 const Token *varDecl =
nullptr;
1189 eq = eq->
link()->next();
1200 const bool isIncrementOrDecrement = (tok->
tokType() == Token::Type::eIncDecOp);
1201 if (!isAssignment && !isInitialization && !isIncrementOrDecrement)
1204 bool isTrivialInit =
false;
1205 if (isInitialization &&
Token::Match(tok,
"%var% { }"))
1206 isTrivialInit =
true;
1223 if (!isInitialization && tok->
astParent() && !tok->
astParent()->isAssignmentOp() && tok->
str() !=
"(") {
1242 if (iteratorToken && iteratorToken->
variable() && iteratorToken->
variable()->typeEndToken()->str().find(
"iterator") != std::string::npos)
1256 std::string bailoutTypeName;
1280 typeName.erase(typeName.begin(), typeName.begin() + 2);
1283 bailoutTypeName = typeName;
1299 if (isInitialization)
1308 if (fwdAnalysis.
unusedValue(expr, start, scopeEnd)) {
1309 if (!bailoutTypeName.empty()) {
1310 if (bailoutTypeName !=
"auto")
1311 reportLibraryCfgError(tok, bailoutTypeName);
1330 for (std::map<nonneg int, Variables::VariableUsage>::const_iterator it = variables.
varUsage().cbegin();
1345 const std::string &varname = usage.
_var->
name();
1375 const Token* parent = nextStmt;
1381 while (nextStmt && nextStmt->
str() !=
";")
1382 nextStmt = nextStmt->
next();
1391 reportLibraryCfgError(vnt, typeName);
1451 logChecker(
"CheckUnusedVar::checkStructMemberUsage");
1472 if (scope.
className.find(
'<') != std::string::npos)
1476 const bool isInherited = std::any_of(symbolDatabase->
scopeList.cbegin(), symbolDatabase->
scopeList.cend(), [&](
const Scope& derivedScope) {
1477 const Type* dType = derivedScope.definedType;
1478 return dType && std::any_of(dType->derivedFrom.cbegin(), dType->derivedFrom.cend(), [&](const Type::BaseInfo& derivedFrom) {
1479 return derivedFrom.type == scope.definedType && derivedFrom.access != AccessControl::Private;
1486 if (var && (var->isExtern() || (var->isGlobal() && !var->isStatic())) && var->typeEndToken()->str() == scope.
className) {
1497 const std::string castPattern(
"( struct| " + scope.
className +
" * ) &| %name%");
1502 const std::string initPattern(
"( struct| " + scope.
className +
" ) {");
1508 tok = tok->tokAt(2);
1527 if (
Token::Match(tok,
". %name%") && !tok->next()->variable() && !tok->next()->function() && tok->next()->str() == var.
name()) {
1532 if (tok->variable() != &var)
1540 std::string prefix =
"struct";
1541 if (scope.
type == Scope::ScopeType::eClass)
1543 else if (scope.
type == Scope::ScopeType::eUnion)
1561 std::pair<const Type *,bool>(type,
false));
1562 bool & withoutSideEffects = found.first->second;
1564 return withoutSideEffects;
1568 return (withoutSideEffects =
false);
1581 nextToken = nextToken->
next();
1583 for (
const Token *initListToken = nextToken;
Token::Match(initListToken,
"[:,] %var% [({]"); initListToken = initListToken->linkAt(2)->next()) {
1584 const Token* varToken = initListToken->
next();
1587 return withoutSideEffects =
false;
1591 for (
const Token* valueToken = initListToken->
tokAt(3); valueToken != valueEnd; valueToken = valueToken->
next()) {
1592 const Variable* initValueVar = valueToken->variable();
1594 return withoutSideEffects =
false;
1596 if ((valueToken->tokType() == Token::Type::eName) ||
1597 (valueToken->tokType() == Token::Type::eLambda) ||
1598 (valueToken->tokType() == Token::Type::eOther)) {
1599 return withoutSideEffects =
false;
1601 const Function* initValueFunc = valueToken->function();
1603 std::list<const Function*> {})) {
1604 return withoutSideEffects =
false;
1611 return (withoutSideEffects =
false);
1618 return (withoutSideEffects =
false);
1623 if (!withoutSideEffects) {
1624 return withoutSideEffects;
1629 return (withoutSideEffects =
true);
1634 const Type* variableType = var.
type();
1635 if (variableType && variableType != type) {
1642 if ((valueType == ValueType::Type::UNKNOWN_TYPE) || (valueType == ValueType::Type::NONSTD))
1653 const std::pair<std::map<const Type *,bool>::iterator,
bool> found=
mIsEmptyTypeMap.insert(
1654 std::pair<const Type *,bool>(type,
false));
1655 bool & emptyType=found.first->second;
1662 return isEmptyType(bi.type);
1667 return (emptyType =
false);
1671 std::list<const Function*> checkedFuncs)
1679 const Variable* argVar = argsToken->variable();
1680 if (argVar && argVar->
isGlobal()) {
1685 bool sideEffectReturnFound =
false;
1686 std::set<const Variable*> pointersToGlobals;
1688 bodyToken = bodyToken->
next()) {
1690 const Variable* bodyVariable = bodyToken->variable();
1696 if (bodyVariable->
isGlobal() || (pointersToGlobals.find(bodyVariable) != pointersToGlobals.end())) {
1703 const Token* assigned_var_token = bodyToken->
tokAt(-3);
1704 if (assigned_var_token && assigned_var_token->
variable()) {
1705 pointersToGlobals.insert(assigned_var_token->
variable());
1712 const Function* bodyFunction = bodyToken->function();
1714 if (std::find(checkedFuncs.cbegin(), checkedFuncs.cend(), bodyFunction) != checkedFuncs.cend()) {
1717 checkedFuncs.push_back(bodyFunction);
1725 const Token* returnValueToken = bodyToken->
next();
1728 sideEffectReturnFound =
true;
1737 sideEffectReturnFound =
true;
1741 if (bodyToken->isNameOnly()) {
1746 return !sideEffectReturnFound;
bool astIsContainer(const Token *tok)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
bool isLikelyStreamRead(const Token *op)
do we see a likely write of rhs through overloaded operator s >> x; a & x;
const Token * findExpressionChanged(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth)
const Token * findAllocFuncCallToken(const Token *expr, const Library &library)
Find a allocation function call in expression, so result of expression is allocated memory/resource.
bool astIsLHS(const Token *tok)
bool isNullOperand(const Token *expr)
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
#define WRONG_DATA(COND, TOK)
Use WRONG_DATA in checkers to mark conditions that check that data is correct.
static const CWE CWE563(563U)
static const Token * doAssignment(Variables &variables, const Token *tok, bool dereference, const Scope *scope)
static const Token * skipBracketsAndMembers(const Token *tok)
static bool isRaiiClassScope(const Scope *classScope)
Is scope a raii class scope.
static const CWE CWE665(665U)
static bool isRaiiClass(const ValueType *valueType, bool cpp, bool defaultReturn=true)
Is ValueType a raii class?
static bool isPartOfClassStructUnion(const Token *tok)
static void useFunctionArgs(const Token *tok, Variables &variables)
static const Token * skipBrackets(const Token *tok)
static bool isVarDecl(const Token *tok)
void unassignedVariableError(const Token *tok, const std::string &varname)
std::map< const Type *, bool > mIsEmptyTypeMap
bool isFunctionWithoutSideEffects(const Function &func, const Token *functionUsageToken, std::list< const Function * > checkedFuncs)
void allocatedButUnusedVariableError(const Token *tok, const std::string &varname)
bool isRecordTypeWithoutSideEffects(const Type *type)
void unusedVariableError(const Token *tok, const std::string &varname)
void unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname, const std::string &prefix="struct")
void checkStructMemberUsage()
Check that all struct members are used
void unreadVariableError(const Token *tok, const std::string &varname, bool modified)
void checkFunctionVariableUsage()
void checkFunctionVariableUsage_iterateScopes(const Scope *const scope, Variables &variables)
Check for unused function variables
bool isVariableWithoutSideEffects(const Variable &var, const Type *type=nullptr)
std::map< const Type *, bool > mIsRecordTypeWithoutSideEffectsMap
bool isEmptyType(const Type *type)
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
const Settings *const mSettings
const Tokenizer *const mTokenizer
void logChecker(const char id[])
log checker
const Token * argDef
function argument start '(' in class definition
const Scope * functionScope
scope of function body
bool isDestructor() const
bool isConstructor() const
Forward data flow analysis for checks.
bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken)
Check if "expr" is used.
static bool ismemory(const int id)
is allocation type memory?
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
TypeCheck getTypeCheck(std::string check, std::string typeName) const
const AllocFunc * getDeallocFuncInfo(const Token *tok) const
get deallocation info for function
const Container * detectContainer(const Token *typeStart) const
std::list< Function > functionList
bool hasInlineOrLambdaFunction() const
std::list< Variable > varlist
std::vector< Scope * > nestedList
const Function * getDestructor() const
const Token * classDef
class/struct/union/namespace token
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
nonneg int numConstructors
bool isExecutable() const
bool checkLibrary
Check for incomplete info in library files?
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
SimpleEnableGroup< Severity > severity
bool isEnabled(T flag) const
const Variable * getVariableFromVarId(nonneg int varId) const
const std::vector< const Variable * > & variableList() const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
The token list that the TokenList generates is a linked-list of this class.
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
bool isAttributeUsed() const
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
bool isExpandedMacro() const
bool isExtendedOp() const
const ValueType * valueType() const
const std::string & strAt(int index) const
bool isAttributeUnused() const
void astOperand1(Token *tok)
void function(const Function *f)
Associate this token with given function.
std::pair< const Token *, const Token * > findExpressionStartEndTokens() const
std::string expressionString() const
bool isUnaryOp(const std::string &s) const
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
const Token * tokAt(int index) const
Token::Type tokType() const
void astOperand2(Token *tok)
void scope(const Scope *s)
Associate this token with given scope.
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
bool isAssignmentOp() const
bool isSplittedVarDeclEq() const
bool isStandardType() const
void variable(const Variable *v)
Associate this token with given variable.
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
nonneg int fileIndex() const
bool isAttributePacked() const
void astParent(Token *tok)
bool isPacked(const Token *bodyStart) const
const Token * tokens() const
bool isC() const
Is the code C.
const SymbolDatabase * getSymbolDatabase() const
bool isCPP() const
Is the code CPP.
Information about a class type.
std::vector< BaseInfo > derivedFrom
enum Type::NeedInitialization needInitialization
enum ValueType::Type type
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
const Scope * typeScope
if the type definition is seen this point out the type scope
const ::Type * smartPointerType
Smart pointer type.
Information about a member variable.
bool isClass() const
Is variable a user defined (or unknown) type.
bool isReference() const
Is reference variable.
std::string getTypeName() const
bool isMaybeUnused() const
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
bool isGlobal() const
Is variable global.
const std::string & name() const
Get name string.
const Token * typeEndToken() const
Get type end token.
bool isArray() const
Is variable an array.
const Token * nameToken() const
Get name token.
bool isPrivate() const
Is variable private.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
const Token * typeStartToken() const
Get type start token.
const std::vector< Dimension > & dimensions() const
Get array dimensions.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
Store information about variable usage.
VariableUsage(const Variable *var=nullptr, VariableType type=standard, bool read=false, bool write=false, bool modified=false, bool allocateMemory=false)
void use()
variable is used.
const Token * _lastAccess
bool unused() const
is variable unused?
std::set< nonneg int > _aliases
std::set< const Scope * > _assignments
This class is used create a list of variables within a function.
void eraseAliases(nonneg int varid)
void writeAll(nonneg int varid, const Token *tok)
void readAll(nonneg int varid, const Token *tok)
void writeAliases(nonneg int varid, const Token *tok)
void modified(nonneg int varid, const Token *tok)
void readAliases(nonneg int varid, const Token *tok)
std::map< nonneg int, VariableUsage > mVarUsage
void use(nonneg int varid, const Token *tok)
void read(nonneg int varid, const Token *tok)
VariableUsage * find(nonneg int varid)
void write(nonneg int varid, const Token *tok)
void clearAliases(nonneg int varid)
void erase(nonneg int varid)
void alias(nonneg int varid1, nonneg int varid2, bool replace)
Alias the 2 given variables.
void eraseAll(nonneg int varid)
void allocateMemory(nonneg int varid, const Token *tok)
const std::map< nonneg int, VariableUsage > & varUsage() const
void addVar(const Variable *var, VariableType type, bool write_)
static void replace(std::string &source, const std::unordered_map< std::string, std::string > &substitutionMap)
@ information
Checking information.
@ error
Programming error.
const Token * getEndOfExprScope(const Token *tok, const Scope *defaultScope=nullptr, bool smallest=true)
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
bool endsWith(const std::string &str, char c)
#define bailout(tokenlist, errorLogger, tok, what)