astutils: Add function that visits nodes in AST tree

This commit is contained in:
Daniel Marjamäki 2018-11-23 06:53:43 +01:00
parent c181d28b1a
commit ecb3c04fba
3 changed files with 46 additions and 13 deletions

View File

@ -28,7 +28,30 @@
#include "valueflow.h"
#include <list>
#include <functional>
#include <stack>
void visitAstNodes(const Token *ast, std::function<ChildrenToVisit(const Token *)> visitor)
{
std::stack<const Token *> tokens;
tokens.push(ast);
while (!tokens.empty()) {
const Token *tok = tokens.top();
tokens.pop();
if (!tok)
continue;
ChildrenToVisit c = visitor(tok);
if (c == ChildrenToVisit::done)
break;
if (c == ChildrenToVisit::op1 || c == ChildrenToVisit::op1_and_op2)
tokens.push(tok->astOperand1());
if (c == ChildrenToVisit::op1 || c == ChildrenToVisit::op1_and_op2)
tokens.push(tok->astOperand2());
}
}
static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign)
{

View File

@ -22,6 +22,7 @@
#define astutilsH
//---------------------------------------------------------------------------
#include <functional>
#include <string>
#include <vector>
@ -32,6 +33,19 @@ class Settings;
class Token;
class Variable;
enum class ChildrenToVisit {
none,
op1,
op2,
op1_and_op2,
done // found what we looked for, don't visit any more children
};
/**
* Visit AST nodes recursively. The order is not "well defined"
*/
void visitAstNodes(const Token *ast, std::function<ChildrenToVisit(const Token *)> visitor);
/** Is expression a 'signed char' if no promotion is used */
bool astIsSignedChar(const Token *tok);
/** Is expression a 'char' if no promotion is used? */

View File

@ -594,28 +594,24 @@ void CheckOther::checkRedundantAssignment()
bool error = oldeq && eq->astOperand1() && isSameExpression(mTokenizer->isCPP(), true, eq->astOperand1(), oldeq->astOperand1(), mSettings->library, true, false);
// Ensure that variable is not used on right side
std::stack<const Token *> tokens;
tokens.push(eq->astOperand2());
while (!tokens.empty()) {
const Token *rhs = tokens.top();
tokens.pop();
if (!rhs)
continue;
tokens.push(rhs->astOperand1());
tokens.push(rhs->astOperand2());
visitAstNodes(eq->astOperand2(),
[&](const Token *rhs) {
if (rhs->varId() == tok->varId()) {
error = false;
break;
return ChildrenToVisit::done;
}
if (Token::Match(rhs->previous(), "%name% (") && nonLocalVolatile(tok->variable())) { // Called function might use the variable
const Function* const func = rhs->function();
const Variable* const var = tok->variable();
if (!var || var->isGlobal() || var->isReference() || ((!func || func->nestedIn) && rhs->strAt(-1) != ".")) {// Global variable, or member function
error = false;
break;
return ChildrenToVisit::done;
}
}
}
return ChildrenToVisit::op1_and_op2;
});
if (error) {
if (printWarning && scope.type == Scope::eSwitch && Token::findmatch(it->second, "default|case", tok))