AST: Always use AST

This commit is contained in:
Daniel Marjamäki 2013-12-09 18:06:19 +01:00
parent be5c00d215
commit 5ba02d2fdd
8 changed files with 136 additions and 450 deletions

View File

@ -125,10 +125,6 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
else if (std::strcmp(argv[i], "--debug-fp") == 0)
_settings->debugFalsePositive = true;
// Experimental AST handling
else if (std::strcmp(argv[i], "--ast") == 0)
_settings->ast = true;
// Inconclusive checking (still in testing phase)
else if (std::strcmp(argv[i], "--inconclusive") == 0)
_settings->inconclusive = true;

View File

@ -203,7 +203,6 @@ void CheckAssignIf::comparison()
if (!_settings->isEnabled("style"))
return;
if (_settings->ast) {
// Experimental code based on AST
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "==|!=")) {
@ -234,32 +233,6 @@ void CheckAssignIf::comparison()
}
}
}
return;
}
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "&|%or% %num% )| ==|!= %num% &&|%oror%|)")) {
const MathLib::bigint num1 = MathLib::toLongNumber(tok->strAt(1));
if (num1 < 0)
continue;
const Token *compareToken = tok->tokAt(2);
if (compareToken->str() == ")") {
if (!Token::Match(compareToken->link()->previous(), "(|%oror%|&&"))
continue;
compareToken = compareToken->next();
}
const MathLib::bigint num2 = MathLib::toLongNumber(compareToken->strAt(1));
if (num2 < 0)
continue;
if ((tok->str() == "&" && (num1 & num2) != num2) ||
(tok->str() == "|" && (num1 | num2) != num2)) {
const std::string& op(compareToken->str());
comparisonError(tok, tok->str(), num1, op, num2, op=="==" ? false : true);
}
}
}
}
void CheckAssignIf::comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result)

View File

@ -1267,16 +1267,6 @@ static std::string invertOperatorForOperandSwap(std::string s)
return s;
}
static bool checkRelation(Relation relation, const std::string &value1, const std::string &value2)
{
return (relation == Equal && MathLib::isEqual(value1, value2)) ||
(relation == NotEqual && MathLib::isNotEqual(value1, value2)) ||
(relation == Less && MathLib::isLess(value1, value2)) ||
(relation == LessEqual && MathLib::isLessEqual(value1, value2)) ||
(relation == More && MathLib::isGreater(value1, value2)) ||
(relation == MoreEqual && MathLib::isGreaterEqual(value1, value2));
}
static bool checkIntRelation(const std::string &op, const MathLib::bigint value1, const MathLib::bigint value2)
{
return (op == "==" && value1 == value2) ||
@ -1295,28 +1285,6 @@ static bool checkFloatRelation(const std::string &op, const double value1, const
(op == "<=" && value1 <= value2);
}
static bool analyzeLogicOperatorCondition(const Condition& c1, const Condition& c2,
bool inv1, bool inv2,
bool varFirst1, bool varFirst2,
const std::string& firstConstant, const std::string& secondConstant,
const Token* op1Tok, const Token* op3Tok,
Relation relation)
{
if (!(c1.position == NA || (c1.position == First && varFirst1) || (c1.position == Second && !varFirst1)))
return false;
if (!(c2.position == NA || (c2.position == First && varFirst2) || (c2.position == Second && !varFirst2)))
return false;
if (!Token::Match(op1Tok, inv1?invertOperatorForOperandSwap(c1.opTokStr).c_str():c1.opTokStr))
return false;
if (!Token::Match(op3Tok, inv2?invertOperatorForOperandSwap(c2.opTokStr).c_str():c2.opTokStr))
return false;
return checkRelation(relation, firstConstant, secondConstant);
}
template<class T> static T getvalue(const int test, const T value1, const T value2)
{
// test:
@ -1368,7 +1336,6 @@ void CheckOther::checkIncorrectLogicOperator()
for (std::size_t ii = 0; ii < functions; ++ii) {
const Scope * scope = symbolDatabase->functionScopes[ii];
if (_settings->ast) {
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (Token::Match(tok, "&&|%oror%")) {
// Comparison #1 (LHS)
@ -1485,207 +1452,6 @@ void CheckOther::checkIncorrectLogicOperator()
}
}
}
continue;
}
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
// Find a pair of comparison expressions with or without parentheses
// with a shared variable and constants and with a logical operator between them.
// e.g. if (x != 3 || x != 4)
const Token *term1Tok = NULL, *term2Tok = NULL;
const Token *op1Tok = NULL, *op2Tok = NULL, *op3Tok = NULL, *nextTok = NULL;
if (Token::Match(tok, "( %any% %comp% %any% ) &&|%oror%")) {
term1Tok = tok->next();
op1Tok = tok->tokAt(2);
op2Tok = tok->tokAt(5);
} else if (Token::Match(tok, "%any% %comp% %any% &&|%oror%")) {
term1Tok = tok;
op1Tok = tok->next();
op2Tok = tok->tokAt(3);
}
if (op2Tok) {
if (Token::Match(op2Tok->next(), "( %any% %comp% %any% ) %any%")) {
term2Tok = op2Tok->tokAt(2);
op3Tok = op2Tok->tokAt(3);
nextTok = op2Tok->tokAt(6);
} else if (Token::Match(op2Tok->next(), "%any% %comp% %any% %any%")) {
term2Tok = op2Tok->next();
op3Tok = op2Tok->tokAt(2);
nextTok = op2Tok->tokAt(4);
}
}
if (nextTok) {
// Find the common variable and the two different-valued constants
std::string firstConstant, secondConstant;
bool varFirst1, varFirst2;
unsigned int varId;
const Token *var1Tok = NULL, *var2Tok = NULL;
if (Token::Match(term1Tok, "%var% %any% %num%")) {
var1Tok = term1Tok;
varId = var1Tok->varId();
if (!varId) {
continue;
}
varFirst1 = true;
firstConstant = term1Tok->strAt(2);
} else if (Token::Match(term1Tok, "%num% %any% %var%")) {
var1Tok = term1Tok->tokAt(2);
varId = var1Tok->varId();
if (!varId) {
continue;
}
varFirst1 = false;
firstConstant = term1Tok->str();
} else {
continue;
}
if (Token::Match(term2Tok, "%var% %any% %num%")) {
var2Tok = term2Tok;
varFirst2 = true;
secondConstant = term2Tok->strAt(2);
} else if (Token::Match(term2Tok, "%num% %any% %var%")) {
var2Tok = term2Tok->tokAt(2);
varFirst2 = false;
secondConstant = term2Tok->str();
} else {
continue;
}
if (varId != var2Tok->varId() || firstConstant.empty() || secondConstant.empty()) {
continue;
}
enum LogicError { AlwaysFalse, AlwaysTrue, FirstTrue, FirstFalse, SecondTrue, SecondFalse };
static const struct LinkedConditions {
const char *before;
Condition c1;
const char *op2TokStr;
Condition c2;
const char *after;
Relation relation;
LogicError error;
} conditions[] = {
{ "!!&&", { NA, "!=" }, "%oror%", { NA, "!=" }, "!!&&", NotEqual, AlwaysTrue }, // (x != 1) || (x != 3) <- always true
{ 0, { NA, "==" }, "&&", { NA, "==" }, 0, NotEqual, AlwaysFalse }, // (x == 1) && (x == 3) <- always false
{ "!!&&", { First, ">" }, "%oror%", { First, "<" }, "!!&&", Less, AlwaysTrue }, // (x > 3) || (x < 10) <- always true
{ "!!&&", { First, ">=" }, "%oror%", { First, "<|<=" }, "!!&&", LessEqual, AlwaysTrue }, // (x >= 3) || (x < 10) <- always true
{ "!!&&", { First, ">" }, "%oror%", { First, "<=" }, "!!&&", LessEqual, AlwaysTrue }, // (x > 3) || (x <= 10) <- always true
{ 0, { First, "<" }, "&&", { First, ">" }, 0, LessEqual, AlwaysFalse }, // (x < 1) && (x > 3) <- always false
{ 0, { First, "<=" }, "&&", { First, ">|>=" }, 0, Less, AlwaysFalse }, // (x <= 1) && (x > 3) <- always false
{ 0, { First, "<" }, "&&", { First, ">=" }, 0, Less, AlwaysFalse }, // (x < 1) && (x >= 3) <- always false
{ 0, { First, ">" }, "&&", { NA, "==" }, 0, MoreEqual, AlwaysFalse }, // (x > 5) && (x == 1) <- always false
{ 0, { First, "<" }, "&&", { NA, "==" }, 0, LessEqual, AlwaysFalse }, // (x < 1) && (x == 3) <- always false
{ 0, { First, ">=" }, "&&", { NA, "==" }, 0, More, AlwaysFalse }, // (x >= 5) && (x == 1) <- always false
{ 0, { First, "<=" }, "&&", { NA, "==" }, 0, Less, AlwaysFalse }, // (x <= 1) && (x == 3) <- always false
{ "!!&&", { NA, "==" }, "%oror%", { First, ">" }, "!!&&", More, SecondTrue }, // (x == 4) || (x > 3) <- second expression always true
{ "!!&&", { NA, "==" }, "%oror%", { First, "<" }, "!!&&", Less, SecondTrue }, // (x == 4) || (x < 5) <- second expression always true
{ "!!&&", { NA, "==" }, "%oror%", { First, ">=" }, "!!&&", MoreEqual, SecondTrue }, // (x == 4) || (x >= 3) <- second expression always true
{ "!!&&", { NA, "==" }, "%oror%", { First, "<=" }, "!!&&", LessEqual, SecondTrue }, // (x == 4) || (x <= 5) <- second expression always true
{ "!!&&", { First, ">" }, "%oror%", { NA, "!=" }, "!!&&", MoreEqual, SecondTrue }, // (x > 5) || (x != 1) <- second expression always true
{ "!!&&", { First, "<" }, "%oror%", { NA, "!=" }, "!!&&", LessEqual, SecondTrue }, // (x < 1) || (x != 3) <- second expression always true
{ "!!&&", { First, ">=" }, "%oror%", { NA, "!=" }, "!!&&", More, SecondTrue }, // (x >= 5) || (x != 1) <- second expression always true
{ "!!&&", { First, "<=" }, "%oror%", { NA, "!=" }, "!!&&", Less, SecondTrue }, // (x <= 1) || (x != 3) <- second expression always true
{ 0, { First, ">" }, "&&", { NA, "!=" }, 0, MoreEqual, SecondTrue }, // (x > 5) && (x != 1) <- second expression always true
{ 0, { First, "<" }, "&&", { NA, "!=" }, 0, LessEqual, SecondTrue }, // (x < 1) && (x != 3) <- second expression always true
{ 0, { First, ">=" }, "&&", { NA, "!=" }, 0, More, SecondTrue }, // (x >= 5) && (x != 1) <- second expression always true
{ 0, { First, "<=" }, "&&", { NA, "!=" }, 0, Less, SecondTrue }, // (x <= 1) && (x != 3) <- second expression always true
{ "!!&&", { First, ">|>=" }, "%oror%", { First, ">|>=" }, "!!&&", LessEqual, SecondTrue }, // (x > 4) || (x > 5) <- second expression always true
{ "!!&&", { First, "<|<=" }, "%oror%", { First, "<|<=" }, "!!&&", MoreEqual, SecondTrue }, // (x < 5) || (x < 4) <- second expression always true
{ 0, { First, ">|>=" }, "&&", { First, ">|>=" }, 0, MoreEqual, SecondTrue }, // (x > 4) && (x > 5) <- second expression always true
{ 0, { First, "<|<=" }, "&&", { First, "<|<=" }, 0, MoreEqual, SecondTrue }, // (x < 5) && (x < 4) <- second expression always true
{ 0, { NA, "==" }, "&&", { NA, "!=" }, 0, NotEqual, SecondTrue }, // (x == 3) && (x != 4) <- second expression always true
{ "!!&&", { NA, "==" }, "%oror%", { NA, "!=" }, "!!&&", NotEqual, SecondTrue }, // (x == 3) || (x != 4) <- second expression always true
{ 0, { NA, "!=" }, "&&", { NA, "==" }, 0, Equal, AlwaysFalse }, // (x != 3) && (x == 3) <- expression always false
{ "!!&&", { NA, "!=" }, "%oror%", { NA, "==" }, "!!&&", Equal, AlwaysTrue }, // (x != 3) || (x == 3) <- expression always true
};
for (unsigned int i = 0; i < (sizeof(conditions) / sizeof(conditions[0])); i++) {
if (!Token::Match(op2Tok, conditions[i].op2TokStr))
continue;
if (conditions[i].before != 0 && !Token::Match(tok->previous(), conditions[i].before))
continue;
if (conditions[i].after != 0 && !Token::Match(nextTok, conditions[i].after))
continue;
if (tok->previous()->isArithmeticalOp() || nextTok->isArithmeticalOp())
continue;
std::string cond1str = var1Tok->str() + " " + (varFirst1?op1Tok->str():invertOperatorForOperandSwap(op1Tok->str())) + " " + firstConstant;
std::string cond2str = var2Tok->str() + " " + (varFirst2?op3Tok->str():invertOperatorForOperandSwap(op3Tok->str())) + " " + secondConstant;
// cond1 op cond2
bool error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, false,
varFirst1, varFirst2, firstConstant, secondConstant,
op1Tok, op3Tok,
conditions[i].relation);
// inv(cond1) op cond2 // invert first condition
if (!error && conditions[i].c1.position != NA)
error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, false,
!varFirst1, varFirst2, firstConstant, secondConstant,
op1Tok, op3Tok,
conditions[i].relation);
// cond1 op inv(cond2) // invert second condition
if (!error && conditions[i].c2.position != NA)
error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, true,
varFirst1, !varFirst2, firstConstant, secondConstant,
op1Tok, op3Tok,
conditions[i].relation);
// inv(cond1) op inv(cond2) // invert both conditions
if (!error && conditions[i].c1.position != NA && conditions[i].c2.position != NA)
error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, true,
!varFirst1, !varFirst2, firstConstant, secondConstant,
op1Tok, op3Tok,
conditions[i].relation);
if (!error)
std::swap(cond1str, cond2str);
// cond2 op cond1 // swap conditions
if (!error)
error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, false,
varFirst2, varFirst1, secondConstant, firstConstant,
op3Tok, op1Tok,
conditions[i].relation);
// cond2 op inv(cond1) // swap conditions; invert first condition
if (!error && conditions[i].c1.position != NA)
error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, false,
!varFirst2, varFirst1, secondConstant, firstConstant,
op3Tok, op1Tok,
conditions[i].relation);
// inv(cond2) op cond1 // swap conditions; invert second condition
if (!error && conditions[i].c2.position != NA)
error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, true,
varFirst2, !varFirst1, secondConstant, firstConstant,
op3Tok, op1Tok,
conditions[i].relation);
// inv(cond2) op inv(cond1) // swap conditions; invert both conditions
if (!error && conditions[i].c1.position != NA && conditions[i].c2.position != NA)
error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, true,
!varFirst2, !varFirst1, secondConstant, firstConstant,
op3Tok, op1Tok,
conditions[i].relation);
if (error) {
if (conditions[i].error == AlwaysFalse || conditions[i].error == AlwaysTrue) {
if (warning) {
const std::string text = cond1str + " " + op2Tok->str() + " " + cond2str;
incorrectLogicOperatorError(term1Tok, text, conditions[i].error == AlwaysTrue);
}
} else {
if (style) {
const std::string text = "If " + cond1str + ", the comparison " + cond2str +
" is always " + ((conditions[i].error == SecondTrue || conditions[i].error == AlwaysTrue) ? "true" : "false") + ".";
redundantConditionError(term1Tok, text);
}
}
break;
}
}
}
}
}
}
@ -3390,7 +3156,6 @@ void CheckOther::checkDuplicateExpression()
if (scope->type != Scope::eFunction)
continue;
if (_settings->ast) {
std::set<std::string> constStandardFunctions;
constStandardFunctions.insert("strcmp");
@ -3405,44 +3170,6 @@ void CheckOther::checkDuplicateExpression()
duplicateExpressionError(tok->astOperand2(), tok->astOperand2(), tok->str());
}
}
continue;
}
complexDuplicateExpressionCheck(constFunctions, scope->classStart, "%or%", "");
complexDuplicateExpressionCheck(constFunctions, scope->classStart, "%oror%", "");
complexDuplicateExpressionCheck(constFunctions, scope->classStart, "&", "%oror%|%or%");
complexDuplicateExpressionCheck(constFunctions, scope->classStart, "&&", "%oror%|%or%");
for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) {
if (Token::Match(tok, ",|=|return|(|&&|%oror% %var% %comp%|- %var% )|&&|%oror%|;|,") &&
tok->strAt(1) == tok->strAt(3)) {
// float == float and float != float are valid NaN checks
// float - float is a valid Inf check
if (Token::Match(tok->tokAt(2), "==|!=|-") && tok->next()->varId()) {
const Variable *var = tok->next()->variable();
if (var && var->typeStartToken() == var->typeEndToken()) {
if (Token::Match(var->typeStartToken(), "float|double"))
continue;
}
}
// If either variable token is an expanded macro then
// don't write the warning
if (tok->next()->isExpandedMacro() || tok->tokAt(3)->isExpandedMacro())
continue;
duplicateExpressionError(tok->next(), tok->tokAt(3), tok->strAt(2));
} else if (Token::Match(tok, ",|=|return|(|&&|%oror% %var% . %var% %comp%|- %var% . %var% )|&&|%oror%|;|,") &&
tok->strAt(1) == tok->strAt(5) && tok->strAt(3) == tok->strAt(7)) {
// If either variable token is an expanded macro then
// don't write the warning
if (tok->next()->isExpandedMacro() || tok->tokAt(6)->isExpandedMacro())
continue;
duplicateExpressionError(tok->next(), tok->tokAt(6), tok->strAt(4));
}
}
}
}

View File

@ -26,7 +26,7 @@
Settings::Settings()
: _terminate(false),
debug(false), debugwarnings(false), debugFalsePositive(false),
ast(false), inconclusive(false), experimental(false),
inconclusive(false), experimental(false),
_errorsOnly(false),
_inlineSuppressions(false),
_verbose(false),

View File

@ -62,9 +62,6 @@ public:
/** @brief Is --debug-fp given? */
bool debugFalsePositive;
/** @brief Experimental AST handling */
bool ast;
/** @brief Inconclusive checks */
bool inconclusive;

View File

@ -2094,8 +2094,6 @@ bool Tokenizer::tokenize(std::istream &code,
}
}
// Experimental AST handling.
if (_settings->ast)
list.createAst();
return true;
@ -3694,8 +3692,6 @@ bool Tokenizer::simplifyTokenList()
tok->deleteNext();
}
// Experimental AST handling.
if (_settings->ast)
list.createAst();
if (_settings->terminated())
@ -3707,7 +3703,6 @@ bool Tokenizer::simplifyTokenList()
if (_settings->_verbose)
_symbolDatabase->printOut("Symbol database");
if (_settings->ast)
list.front()->printAst();
}

View File

@ -44,7 +44,6 @@ private:
errout.str("");
Settings settings;
settings.ast = true;
settings.addEnabled("style");
// Tokenize..

View File

@ -202,7 +202,6 @@ private:
if (!settings) {
static Settings _settings;
settings = &_settings;
_settings.ast = true;
}
settings->addEnabled("style");
settings->addEnabled("warning");