"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/astutils.cpp" between
cppcheck-1.86.tar.gz and cppcheck-1.87.tar.gz

About: Cppcheck is a static analysis tool for C/C++ code. It checks for memory leaks, mismatching allocation-deallocation, buffer overrun, and many more.

astutils.cpp  (cppcheck-1.86):astutils.cpp  (cppcheck-1.87)
/* /*
* Cppcheck - A tool for static C/C++ code analysis * Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2018 Cppcheck team. * Copyright (C) 2007-2019 Cppcheck team.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
skipping to change at line 48 skipping to change at line 48
tokens.pop(); tokens.pop();
if (!tok) if (!tok)
continue; continue;
ChildrenToVisit c = visitor(tok); ChildrenToVisit c = visitor(tok);
if (c == ChildrenToVisit::done) if (c == ChildrenToVisit::done)
break; break;
if (c == ChildrenToVisit::op1 || c == ChildrenToVisit::op1_and_op2) if (c == ChildrenToVisit::op1 || c == ChildrenToVisit::op1_and_op2)
tokens.push(tok->astOperand1()); tokens.push(tok->astOperand1());
if (c == ChildrenToVisit::op1 || c == ChildrenToVisit::op1_and_op2) if (c == ChildrenToVisit::op2 || c == ChildrenToVisit::op1_and_op2)
tokens.push(tok->astOperand2()); tokens.push(tok->astOperand2());
} }
} }
static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign) static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign)
{ {
if (!tok) if (!tok)
return false; return false;
const ValueType *valueType = tok->valueType(); const ValueType *valueType = tok->valueType();
if (!valueType) if (!valueType)
skipping to change at line 167 skipping to change at line 167
ret = tok; ret = tok;
} else if (comp == "==" && rhs == std::string("0")) { } else if (comp == "==" && rhs == std::string("0")) {
if (tok->str() == "!") { if (tok->str() == "!") {
ret = tok->astOperand1(); ret = tok->astOperand1();
// handle (!(x!=0)) as (x==0) // handle (!(x!=0)) as (x==0)
astIsVariableComparison(ret, "!=", "0", &ret); astIsVariableComparison(ret, "!=", "0", &ret);
} }
} }
while (ret && ret->str() == ".") while (ret && ret->str() == ".")
ret = ret->astOperand2(); ret = ret->astOperand2();
if (ret && ret->varId() == 0U) if (ret && ret->str() == "=" && ret->astOperand1() && ret->astOperand1()->va
rId())
ret = ret->astOperand1();
else if (ret && ret->varId() == 0U)
ret = nullptr; ret = nullptr;
if (vartok) if (vartok)
*vartok = ret; *vartok = ret;
return ret; return ret;
} }
static bool hasToken(const Token * startTok, const Token * stopTok, const Token * tok) static bool hasToken(const Token * startTok, const Token * stopTok, const Token * tok)
{ {
for (const Token * tok2 = startTok; tok2 != stopTok; tok2 = tok2->next()) { for (const Token * tok2 = startTok; tok2 != stopTok; tok2 = tok2->next()) {
if (tok2 == tok) if (tok2 == tok)
skipping to change at line 372 skipping to change at line 374
return isSameExpression(cpp, macro, tok1->astOperand1()->astOperand1(), tok2, library, pure, followVar, errors); return isSameExpression(cpp, macro, tok1->astOperand1()->astOperand1(), tok2, library, pure, followVar, errors);
} }
if (Token::simpleMatch(tok2, "!") && Token::simpleMatch(tok2->astOperand1(), "!") && !Token::simpleMatch(tok2->astParent(), "=")) { if (Token::simpleMatch(tok2, "!") && Token::simpleMatch(tok2->astOperand1(), "!") && !Token::simpleMatch(tok2->astParent(), "=")) {
return isSameExpression(cpp, macro, tok1, tok2->astOperand1()->astOperan d1(), library, pure, followVar, errors); return isSameExpression(cpp, macro, tok1, tok2->astOperand1()->astOperan d1(), library, pure, followVar, errors);
} }
// Follow variable // Follow variable
if (followVar && tok1->str() != tok2->str() && (Token::Match(tok1, "%var%") || Token::Match(tok2, "%var%"))) { if (followVar && tok1->str() != tok2->str() && (Token::Match(tok1, "%var%") || Token::Match(tok2, "%var%"))) {
const Token * varTok1 = followVariableExpression(tok1, cpp, tok2); const Token * varTok1 = followVariableExpression(tok1, cpp, tok2);
if (varTok1->str() == tok2->str()) { if (varTok1->str() == tok2->str()) {
followVariableExpressionError(tok1, varTok1, errors); followVariableExpressionError(tok1, varTok1, errors);
return isSameExpression(cpp, macro, varTok1, tok2, library, true, er rors); return isSameExpression(cpp, macro, varTok1, tok2, library, true, fo llowVar, errors);
} }
const Token * varTok2 = followVariableExpression(tok2, cpp, tok1); const Token * varTok2 = followVariableExpression(tok2, cpp, tok1);
if (tok1->str() == varTok2->str()) { if (tok1->str() == varTok2->str()) {
followVariableExpressionError(tok2, varTok2, errors); followVariableExpressionError(tok2, varTok2, errors);
return isSameExpression(cpp, macro, tok1, varTok2, library, true, er rors); return isSameExpression(cpp, macro, tok1, varTok2, library, true, fo llowVar, errors);
} }
if (varTok1->str() == varTok2->str()) { if (varTok1->str() == varTok2->str()) {
followVariableExpressionError(tok1, varTok1, errors); followVariableExpressionError(tok1, varTok1, errors);
followVariableExpressionError(tok2, varTok2, errors); followVariableExpressionError(tok2, varTok2, errors);
return isSameExpression(cpp, macro, varTok1, varTok2, library, true, errors); return isSameExpression(cpp, macro, varTok1, varTok2, library, true, followVar, errors);
} }
} }
if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->or iginalName() != tok2->originalName()) { if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->or iginalName() != tok2->originalName()) {
if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) || if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
(Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) { (Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
return isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOp erand2(), library, pure, followVar, errors) && return isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOp erand2(), library, pure, followVar, errors) &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOp erand1(), library, pure, followVar, errors); isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOp erand1(), library, pure, followVar, errors);
} }
return false; return false;
} }
skipping to change at line 770 skipping to change at line 772
prev = prev->previous(); prev = prev->previous();
if (Token::simpleMatch(prev, "}")) { if (Token::simpleMatch(prev, "}")) {
if (Token::simpleMatch(prev->link()->tokAt(-2), "} else {")) if (Token::simpleMatch(prev->link()->tokAt(-2), "} else {"))
return isReturnScope(prev) && isReturnScope(prev->link()->tokAt(-2)) ; return isReturnScope(prev) && isReturnScope(prev->link()->tokAt(-2)) ;
if (Token::simpleMatch(prev->link()->previous(), ") {") && if (Token::simpleMatch(prev->link()->previous(), ") {") &&
Token::simpleMatch(prev->link()->linkAt(-1)->previous(), "switch (") && Token::simpleMatch(prev->link()->linkAt(-1)->previous(), "switch (") &&
!Token::findsimplematch(prev->link(), "break", prev)) { !Token::findsimplematch(prev->link(), "break", prev)) {
return true; return true;
} }
if (Token::simpleMatch(prev->link()->previous(), ") {") && if (Token::Match(prev->link()->astTop(), "return|throw"))
Token::simpleMatch(prev->link()->linkAt(-1)->previous(), "return (")
) {
return true; return true;
}
if (Token::Match(prev->link()->previous(), "[;{}] {")) if (Token::Match(prev->link()->previous(), "[;{}] {"))
return isReturnScope(prev); return isReturnScope(prev);
} else if (Token::simpleMatch(prev, ";")) { } else if (Token::simpleMatch(prev, ";")) {
// noreturn function // noreturn function
if (Token::simpleMatch(prev->previous(), ") ;") && Token::Match(prev->li nkAt(-1)->tokAt(-2), "[;{}] %name% (")) if (Token::simpleMatch(prev->previous(), ") ;") && Token::Match(prev->li nkAt(-1)->tokAt(-2), "[;{}] %name% ("))
return true; return true;
if (Token::simpleMatch(prev->previous(), ") ;") && prev->previous()->lin
k() &&
Token::Match(prev->previous()->link()->astTop(), "return|throw"))
return true;
if (Token::Match(prev->previous()->astTop(), "return|throw"))
return true;
// return/goto statement // return/goto statement
prev = prev->previous(); prev = prev->previous();
while (prev && !Token::Match(prev, ";|{|}|return|goto|throw|continue|bre ak")) while (prev && !Token::Match(prev, ";|{|}|return|goto|throw|continue|bre ak"))
prev = prev->previous(); prev = prev->previous();
return prev && prev->isName(); return prev && prev->isName();
} }
return false; return false;
} }
bool isVariableChangedByFunctionCall(const Token *tok, unsigned int varid, const Settings *settings, bool *inconclusive) bool isVariableChangedByFunctionCall(const Token *tok, unsigned int varid, const Settings *settings, bool *inconclusive)
skipping to change at line 1035 skipping to change at line 1040
parent = parent->astParent(); parent = parent->astParent();
if (parent->astParent() && !Token::Match(parent->astParent(), "%oror%|&&|(|, |!")) if (parent->astParent() && !Token::Match(parent->astParent(), "%oror%|&&|(|, |!"))
return false; return false;
if (op->str() == "&" && parent->astParent()) if (op->str() == "&" && parent->astParent())
return false; return false;
if (!parent->astOperand1() || !parent->astOperand2()) if (!parent->astOperand1() || !parent->astOperand2())
return false; return false;
return (!parent->astOperand1()->valueType() || !parent->astOperand1()->value Type()->isIntegral()); return (!parent->astOperand1()->valueType() || !parent->astOperand1()->value Type()->isIntegral());
} }
bool isCPPCast(const Token* tok)
{
return tok && Token::simpleMatch(tok->previous(), "> (") && tok->astOperand2
() && tok->astOperand1() && tok->astOperand1()->str().find("_cast") != std::stri
ng::npos;
}
bool isConstVarExpression(const Token *tok)
{
if (!tok)
return false;
if (Token::simpleMatch(tok->previous(), "sizeof ("))
return true;
if (Token::Match(tok->previous(), "%name% (")) {
std::vector<const Token *> args = getArguments(tok);
return std::all_of(args.begin(), args.end(), &isConstVarExpression);
}
if (isCPPCast(tok)) {
return isConstVarExpression(tok->astOperand2());
}
if (Token::Match(tok, "( %type%"))
return isConstVarExpression(tok->astOperand1());
if (Token::Match(tok, "%cop%")) {
if (tok->astOperand1() && !isConstVarExpression(tok->astOperand1()))
return false;
if (tok->astOperand2() && !isConstVarExpression(tok->astOperand2()))
return false;
return true;
}
if (Token::Match(tok, "%bool%|%num%|%str%|%char%|nullptr|NULL"))
return true;
if (tok->isEnumerator())
return true;
if (tok->variable())
return tok->variable()->isConst();
return false;
}
static bool nonLocal(const Variable* var) static bool nonLocal(const Variable* var)
{ {
return !var || (!var->isLocal() && !var->isArgument()) || var->isStatic() || var->isReference(); return !var || (!var->isLocal() && !var->isArgument()) || var->isStatic() || var->isReference() || var->isExtern();
} }
static bool hasFunctionCall(const Token *tok) static bool hasFunctionCall(const Token *tok)
{ {
if (!tok) if (!tok)
return false; return false;
if (Token::Match(tok, "%name% (")) if (Token::Match(tok, "%name% ("))
// todo, const/pure function? // todo, const/pure function?
return true; return true;
return hasFunctionCall(tok->astOperand1()) || hasFunctionCall(tok->astOperan d2()); return hasFunctionCall(tok->astOperand1()) || hasFunctionCall(tok->astOperan d2());
skipping to change at line 1059 skipping to change at line 1100
struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<unsigned int> &exprVarI ds, bool local) struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<unsigned int> &exprVarI ds, bool local)
{ {
// Parse the given tokens // Parse the given tokens
for (const Token *tok = startToken; tok != endToken; tok = tok->next()) { for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
if (Token::simpleMatch(tok, "try {")) { if (Token::simpleMatch(tok, "try {")) {
// TODO: handle try // TODO: handle try
return Result(Result::Type::BAILOUT); return Result(Result::Type::BAILOUT);
} }
if (tok->str() == "}" && (tok->scope()->type == Scope::eFor || tok->scop
e()->type == Scope::eWhile)) {
// TODO: handle loops better
return Result(Result::Type::BAILOUT);
}
if (Token::simpleMatch(tok, "break ;")) { if (Token::simpleMatch(tok, "break ;")) {
return Result(Result::Type::BREAK, tok); return Result(Result::Type::BREAK, tok);
} }
if (Token::Match(tok, "continue|return|throw|goto")) { if (Token::simpleMatch(tok, "goto"))
return Result(Result::Type::BAILOUT);
if (tok->str() == "continue")
// TODO
return Result(Result::Type::BAILOUT);
if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
tok = lambdaEndToken;
const Result lambdaResult = checkRecursive(expr, lambdaEndToken->lin
k()->next(), lambdaEndToken, exprVarIds, local);
if (lambdaResult.type == Result::Type::READ || lambdaResult.type ==
Result::Type::BAILOUT)
return lambdaResult;
}
if (Token::Match(tok, "return|throw")) {
// TODO: Handle these better // TODO: Handle these better
// Is expr variable used in expression?
const Token *end = tok->findExpressionStartEndTokens().second->next(
);
for (const Token *tok2 = tok; tok2 != end; tok2 = tok2->next()) {
if (!local && Token::Match(tok2, "%name% ("))
return Result(Result::Type::READ);
if (tok2->varId() && exprVarIds.find(tok2->varId()) != exprVarId
s.end())
return Result(Result::Type::READ);
}
return Result(Result::Type::RETURN); return Result(Result::Type::RETURN);
} }
if (tok->str() == "}") {
// Known value => possible value
if (tok->scope() == expr->scope())
mValueFlowKnown = false;
Scope::ScopeType scopeType = tok->scope()->type;
if (scopeType == Scope::eWhile || scopeType == Scope::eFor || scopeT
ype == Scope::eDo) {
// check condition
const Token *conditionStart = nullptr;
const Token *conditionEnd = nullptr;
if (Token::simpleMatch(tok->link()->previous(), ") {")) {
conditionEnd = tok->link()->previous();
conditionStart = conditionEnd->link();
} else if (Token::simpleMatch(tok->link()->previous(), "do {") &
& Token::simpleMatch(tok, "} while (")) {
conditionStart = tok->tokAt(2);
conditionEnd = conditionStart->link();
}
if (conditionStart && conditionEnd) {
bool used = false;
for (const Token *condTok = conditionStart; condTok != condi
tionEnd; condTok = condTok->next()) {
if (exprVarIds.find(condTok->varId()) != exprVarIds.end(
))
used = true;
}
if (used)
return Result(Result::Type::BAILOUT);
}
// check loop body again..
const struct FwdAnalysis::Result &result = checkRecursive(expr,
tok->link(), tok, exprVarIds, local);
if (result.type == Result::Type::BAILOUT || result.type == Resul
t::Type::READ)
return result;
}
}
if (Token::simpleMatch(tok, "else {")) if (Token::simpleMatch(tok, "else {"))
tok = tok->linkAt(1); tok = tok->linkAt(1);
if (Token::simpleMatch(tok, "asm (")) { if (Token::simpleMatch(tok, "asm ("))
return Result(Result::Type::BAILOUT);
if (mWhat == What::ValueFlow && Token::Match(tok, "while|for (")) {
// TODO: only bailout if expr is reassigned in loop
return Result(Result::Type::BAILOUT); return Result(Result::Type::BAILOUT);
} }
if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok-> linkAt(1), ") {")) { if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok-> linkAt(1), ") {")) {
// TODO: this is a quick bailout // TODO: this is a quick bailout
return Result(Result::Type::BAILOUT); return Result(Result::Type::BAILOUT);
} }
if (expr->isName() && Token::Match(tok, "%name% (") && tok->str().find("
<") != std::string::npos && tok->str().find(expr->str()) != std::string::npos)
return Result(Result::Type::BAILOUT);
if (exprVarIds.find(tok->varId()) != exprVarIds.end()) { if (exprVarIds.find(tok->varId()) != exprVarIds.end()) {
const Token *parent = tok; const Token *parent = tok;
while (Token::Match(parent->astParent(), ".|::|[")) bool other = false;
bool same = tok->astParent() && isSameExpression(mCpp, false, expr,
tok, mLibrary, false, false, nullptr);
while (!same && Token::Match(parent->astParent(), "*|.|::|[")) {
parent = parent->astParent(); parent = parent->astParent();
if (parent && isSameExpression(mCpp, false, expr, parent, mLibra
ry, false, false, nullptr)) {
same = true;
if (mWhat == What::ValueFlow) {
KnownAndToken v;
v.known = mValueFlowKnown;
v.token = parent;
mValueFlow.push_back(v);
}
}
if (Token::Match(parent, ". %var%") && parent->next()->varId() &
& exprVarIds.find(parent->next()->varId()) == exprVarIds.end()) {
other = true;
break;
}
}
if (mWhat != What::ValueFlow && same && Token::simpleMatch(parent->a
stParent(), "[") && parent == parent->astParent()->astOperand2()) {
return Result(Result::Type::READ);
}
if (other)
continue;
if (Token::simpleMatch(parent->astParent(), "=") && parent == parent ->astParent()->astOperand1()) { if (Token::simpleMatch(parent->astParent(), "=") && parent == parent ->astParent()->astOperand1()) {
if (!local && hasFunctionCall(parent->astParent()->astOperand2() )) { if (!local && hasFunctionCall(parent->astParent()->astOperand2() )) {
// TODO: this is a quick bailout // TODO: this is a quick bailout
return Result(Result::Type::BAILOUT); return Result(Result::Type::BAILOUT);
} }
if (hasOperand(parent->astParent()->astOperand2(), expr)) { if (hasOperand(parent->astParent()->astOperand2(), expr)) {
if (mReassign) if (mWhat == What::Reassign)
return Result(Result::Type::READ); return Result(Result::Type::READ);
continue; continue;
} }
const bool reassign = isSameExpression(mCpp, false, expr, parent , mLibrary, false, false, nullptr); const bool reassign = isSameExpression(mCpp, false, expr, parent , mLibrary, false, false, nullptr);
if (reassign) if (reassign)
return Result(Result::Type::WRITE, parent->astParent()); return Result(Result::Type::WRITE, parent->astParent());
return Result(Result::Type::READ); return Result(Result::Type::READ);
} else if (Token::Match(parent->astParent(), "%assign%") && !parent-
>astParent()->astParent() && parent == parent->astParent()->astOperand1()) {
continue;
} else { } else {
// TODO: this is a quick bailout // TODO: this is a quick bailout
return Result(Result::Type::BAILOUT); return Result(Result::Type::BAILOUT, parent->astParent());
} }
} }
if (Token::Match(tok, ") {")) { if (Token::simpleMatch(tok, ") {")) {
if (Token::simpleMatch(tok->link()->previous(), "switch ("))
// TODO: parse switch
return Result(Result::Type::BAILOUT);
const Result &result1 = checkRecursive(expr, tok->tokAt(2), tok->lin kAt(1), exprVarIds, local); const Result &result1 = checkRecursive(expr, tok->tokAt(2), tok->lin kAt(1), exprVarIds, local);
if (result1.type == Result::Type::READ || result1.type == Result::Ty pe::BAILOUT) if (result1.type == Result::Type::READ || result1.type == Result::Ty pe::BAILOUT)
return result1; return result1;
if (mWhat == What::ValueFlow && result1.type == Result::Type::WRITE)
mValueFlowKnown = false;
if (Token::simpleMatch(tok->linkAt(1), "} else {")) { if (Token::simpleMatch(tok->linkAt(1), "} else {")) {
const Token *elseStart = tok->linkAt(1)->tokAt(2); const Token *elseStart = tok->linkAt(1)->tokAt(2);
const Result &result2 = checkRecursive(expr, elseStart, elseStar t->link(), exprVarIds, local); const Result &result2 = checkRecursive(expr, elseStart, elseStar t->link(), exprVarIds, local);
if (mWhat == What::ValueFlow && result2.type == Result::Type::WR
ITE)
mValueFlowKnown = false;
if (result2.type == Result::Type::READ || result2.type == Result ::Type::BAILOUT) if (result2.type == Result::Type::READ || result2.type == Result ::Type::BAILOUT)
return result2; return result2;
if (result1.type == Result::Type::WRITE && result2.type == Resul t::Type::WRITE) if (result1.type == Result::Type::WRITE && result2.type == Resul t::Type::WRITE)
return result1; return result1;
tok = elseStart->link(); tok = elseStart->link();
} else { } else {
tok = tok->linkAt(1); tok = tok->linkAt(1);
} }
} }
} }
return Result(Result::Type::NONE); return Result(Result::Type::NONE);
} }
bool FwdAnalysis::isGlobalData(const Token *expr) const
{
bool globalData = false;
visitAstNodes(expr,
[&](const Token *tok) {
if (tok->varId() && !tok->variable()) {
// Bailout, this is probably global
globalData = true;
return ChildrenToVisit::none;
}
if (tok->originalName() == "->") {
// TODO check if pointer points at local data
globalData = true;
return ChildrenToVisit::none;
} else if (Token::Match(tok, "[*[]") && tok->astOperand1() && tok->astOp
erand1()->variable()) {
// TODO check if pointer points at local data
const Variable *lhsvar = tok->astOperand1()->variable();
const ValueType *lhstype = tok->astOperand1()->valueType();
if (lhsvar->isPointer()) {
globalData = true;
return ChildrenToVisit::none;
} else if (lhsvar->isArgument() && lhsvar->isArray()) {
globalData = true;
return ChildrenToVisit::none;
} else if (lhsvar->isArgument() && (!lhstype || (lhstype->type <= Va
lueType::Type::VOID && !lhstype->container))) {
globalData = true;
return ChildrenToVisit::none;
}
}
if (tok->varId() == 0 && tok->isName() && tok->previous()->str() != ".")
{
globalData = true;
return ChildrenToVisit::none;
}
if (tok->variable()) {
// TODO : Check references
if (tok->variable()->isReference() && tok != tok->variable()->nameTo
ken()) {
globalData = true;
return ChildrenToVisit::none;
}
if (tok->variable()->isExtern()) {
globalData = true;
return ChildrenToVisit::none;
}
if (tok->previous()->str() != "." && !tok->variable()->isLocal() &&
!tok->variable()->isArgument()) {
globalData = true;
return ChildrenToVisit::none;
}
if (tok->variable()->isArgument() && tok->variable()->isPointer() &&
tok != expr) {
globalData = true;
return ChildrenToVisit::none;
}
if (tok->variable()->isPointerArray()) {
globalData = true;
return ChildrenToVisit::none;
}
}
// Unknown argument type => it might be some reference type..
if (mCpp && tok->str() == "." && tok->astOperand1() && tok->astOperand1(
)->variable() && !tok->astOperand1()->valueType()) {
globalData = true;
return ChildrenToVisit::none;
}
if (Token::Match(tok, ".|["))
return ChildrenToVisit::op1;
return ChildrenToVisit::op1_and_op2;
});
return globalData;
}
FwdAnalysis::Result FwdAnalysis::check(const Token *expr, const Token *startToke n, const Token *endToken) FwdAnalysis::Result FwdAnalysis::check(const Token *expr, const Token *startToke n, const Token *endToken)
{ {
// all variable ids in expr. // all variable ids in expr.
std::set<unsigned int> exprVarIds; std::set<unsigned int> exprVarIds;
bool local = true; bool local = true;
visitAstNodes(expr, visitAstNodes(expr,
[&](const Token *tok) { [&](const Token *tok) {
if (tok->varId() == 0 && tok->isName() && tok->previous()->str() != ".")
// unknown variables are not local
local = false;
if (tok->varId() > 0) { if (tok->varId() > 0) {
exprVarIds.insert(tok->varId()); exprVarIds.insert(tok->varId());
if (!Token::simpleMatch(tok->previous(), ".")) if (!Token::simpleMatch(tok->previous(), ".")) {
const Variable *var = tok->variable();
if (var && var->isReference() && var->isLocal() && Token::Match(
var->nameToken(), "%var% [=(]") && !isGlobalData(var->nameToken()->next()->astOp
erand2()))
return ChildrenToVisit::none;
local &= !nonLocal(tok->variable()); local &= !nonLocal(tok->variable());
}
} }
return ChildrenToVisit::op1_and_op2; return ChildrenToVisit::op1_and_op2;
}); });
// In unused values checking we do not want to check assignments to
// global data.
if (mWhat == What::UnusedValue && isGlobalData(expr))
return Result(FwdAnalysis::Result::Type::BAILOUT);
Result result = checkRecursive(expr, startToken, endToken, exprVarIds, local ); Result result = checkRecursive(expr, startToken, endToken, exprVarIds, local );
// Break => continue checking in outer scope // Break => continue checking in outer scope
while (result.type == FwdAnalysis::Result::Type::BREAK) { while (result.type == FwdAnalysis::Result::Type::BREAK) {
const Scope *s = result.token->scope(); const Scope *s = result.token->scope();
while (s->type == Scope::eIf) while (s->type == Scope::eIf)
s = s->nestedIn; s = s->nestedIn;
if (s->type != Scope::eSwitch) if (s->type != Scope::eSwitch && s->type != Scope::eWhile && s->type != Scope::eFor)
break; break;
result = checkRecursive(expr, s->bodyEnd->next(), endToken, exprVarIds, local); result = checkRecursive(expr, s->bodyEnd->next(), endToken, exprVarIds, local);
} }
return result; return result;
} }
bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const
{ {
if (!tok) if (!tok)
return false; return false;
if (isSameExpression(mCpp, false, tok, lhs, mLibrary, false, false, nullptr) ) if (isSameExpression(mCpp, false, tok, lhs, mLibrary, false, false, nullptr) )
return true; return true;
return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs); return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs);
} }
const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, c onst Token *endToken) const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, c onst Token *endToken)
{ {
mReassign = true; mWhat = What::Reassign;
Result result = check(expr, startToken, endToken); Result result = check(expr, startToken, endToken);
return result.type == FwdAnalysis::Result::Type::WRITE ? result.token : null ptr; return result.type == FwdAnalysis::Result::Type::WRITE ? result.token : null ptr;
} }
bool FwdAnalysis::unusedValue(const Token *expr, const Token *startToken, const
Token *endToken)
{
mWhat = What::UnusedValue;
Result result = check(expr, startToken, endToken);
return (result.type == FwdAnalysis::Result::Type::NONE || result.type == Fwd
Analysis::Result::Type::RETURN) && !possiblyAliased(expr, startToken);
}
std::vector<FwdAnalysis::KnownAndToken> FwdAnalysis::valueFlow(const Token *expr
, const Token *startToken, const Token *endToken)
{
mWhat = What::ValueFlow;
mValueFlowKnown = true;
check(expr, startToken, endToken);
return mValueFlow;
}
bool FwdAnalysis::possiblyAliased(const Token *expr, const Token *startToken) co
nst
{
if (expr->isUnaryOp("*"))
return true;
const bool macro = false;
const bool pure = false;
const bool followVar = false;
for (const Token *tok = startToken; tok; tok = tok->previous()) {
if (tok->str() == "{" && tok->scope()->type == Scope::eFunction)
break;
if (Token::Match(tok, "%name% (") && !Token::Match(tok, "if|while|for"))
{
// Is argument passed by reference?
const std::vector<const Token*> args = getArguments(tok);
for (unsigned int argnr = 0; argnr < args.size(); ++argnr) {
if (!Token::Match(args[argnr], "%name%|.|::"))
continue;
if (tok->function() && tok->function()->getArgumentVar(argnr) &&
!tok->function()->getArgumentVar(argnr)->isReference() && !tok->function()->isC
onst())
continue;
for (const Token *subexpr = expr; subexpr; subexpr = subexpr->as
tOperand1()) {
if (isSameExpression(mCpp, macro, subexpr, args[argnr], mLib
rary, pure, followVar))
return true;
}
}
continue;
}
const Token *addrOf = nullptr;
if (Token::Match(tok, "& %name% ="))
addrOf = tok->tokAt(2)->astOperand2();
else if (tok->isUnaryOp("&"))
addrOf = tok->astOperand1();
else if (Token::simpleMatch(tok, "std :: ref ("))
addrOf = tok->tokAt(3)->astOperand2();
else
continue;
for (const Token *subexpr = expr; subexpr; subexpr = subexpr->astOperand
1()) {
if (isSameExpression(mCpp, macro, subexpr, addrOf, mLibrary, pure, f
ollowVar))
return true;
}
}
return false;
}
bool FwdAnalysis::isNullOperand(const Token *expr)
{
if (!expr)
return false;
if (Token::Match(expr, "( %name% %name%| * )") && Token::Match(expr->astOper
and1(), "0|NULL|nullptr"))
return true;
return Token::Match(expr, "NULL|nullptr");
}
 End of changes. 33 change blocks. 
26 lines changed or deleted 264 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)