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) else if (std::strcmp(argv[i], "--debug-fp") == 0)
_settings->debugFalsePositive = true; _settings->debugFalsePositive = true;
// Experimental AST handling
else if (std::strcmp(argv[i], "--ast") == 0)
_settings->ast = true;
// Inconclusive checking (still in testing phase) // Inconclusive checking (still in testing phase)
else if (std::strcmp(argv[i], "--inconclusive") == 0) else if (std::strcmp(argv[i], "--inconclusive") == 0)
_settings->inconclusive = true; _settings->inconclusive = true;

View File

@ -203,60 +203,33 @@ void CheckAssignIf::comparison()
if (!_settings->isEnabled("style")) if (!_settings->isEnabled("style"))
return; return;
if (_settings->ast) { // Experimental code based on AST
// Experimental code based on AST
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "==|!=")) {
const Token *expr1 = tok->astOperand1();
const Token *expr2 = tok->astOperand2();
if (!expr1 || !expr2)
continue;
if (expr1->isNumber())
std::swap(expr1,expr2);
if (!expr2->isNumber())
continue;
const MathLib::bigint num2 = MathLib::toLongNumber(expr2->str());
if (num2 < 0)
continue;
if (!Token::Match(expr1,"[&|]"))
continue;
std::list<MathLib::bigint> numbers;
getnumchildren(expr1, numbers);
for (std::list<MathLib::bigint>::const_iterator num = numbers.begin(); num != numbers.end(); ++num) {
const MathLib::bigint num1 = *num;
if (num1 < 0)
continue;
if ((expr1->str() == "&" && (num1 & num2) != num2) ||
(expr1->str() == "|" && (num1 | num2) != num2)) {
const std::string& op(tok->str());
comparisonError(expr1, expr1->str(), num1, op, num2, op=="==" ? false : true);
}
}
}
}
return;
}
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "&|%or% %num% )| ==|!= %num% &&|%oror%|)")) { if (Token::Match(tok, "==|!=")) {
const MathLib::bigint num1 = MathLib::toLongNumber(tok->strAt(1)); const Token *expr1 = tok->astOperand1();
if (num1 < 0) const Token *expr2 = tok->astOperand2();
if (!expr1 || !expr2)
continue; continue;
if (expr1->isNumber())
const Token *compareToken = tok->tokAt(2); std::swap(expr1,expr2);
if (compareToken->str() == ")") { if (!expr2->isNumber())
if (!Token::Match(compareToken->link()->previous(), "(|%oror%|&&")) continue;
continue; const MathLib::bigint num2 = MathLib::toLongNumber(expr2->str());
compareToken = compareToken->next();
}
const MathLib::bigint num2 = MathLib::toLongNumber(compareToken->strAt(1));
if (num2 < 0) if (num2 < 0)
continue; continue;
if (!Token::Match(expr1,"[&|]"))
if ((tok->str() == "&" && (num1 & num2) != num2) || continue;
(tok->str() == "|" && (num1 | num2) != num2)) { std::list<MathLib::bigint> numbers;
const std::string& op(compareToken->str()); getnumchildren(expr1, numbers);
comparisonError(tok, tok->str(), num1, op, num2, op=="==" ? false : true); for (std::list<MathLib::bigint>::const_iterator num = numbers.begin(); num != numbers.end(); ++num) {
const MathLib::bigint num1 = *num;
if (num1 < 0)
continue;
if ((expr1->str() == "&" && (num1 & num2) != num2) ||
(expr1->str() == "|" && (num1 | num2) != num2)) {
const std::string& op(tok->str());
comparisonError(expr1, expr1->str(), num1, op, num2, op=="==" ? false : true);
}
} }
} }
} }

View File

@ -1267,16 +1267,6 @@ static std::string invertOperatorForOperandSwap(std::string s)
return 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) static bool checkIntRelation(const std::string &op, const MathLib::bigint value1, const MathLib::bigint value2)
{ {
return (op == "==" && value1 == value2) || return (op == "==" && value1 == value2) ||
@ -1295,28 +1285,6 @@ static bool checkFloatRelation(const std::string &op, const double value1, const
(op == "<=" && value1 <= value2); (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) template<class T> static T getvalue(const int test, const T value1, const T value2)
{ {
// test: // test:
@ -1368,321 +1336,119 @@ void CheckOther::checkIncorrectLogicOperator()
for (std::size_t ii = 0; ii < functions; ++ii) { for (std::size_t ii = 0; ii < functions; ++ii) {
const Scope * scope = symbolDatabase->functionScopes[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)
const Token *comp1 = tok->astOperand1();
if (comp1 && comp1->str() == tok->str())
comp1 = comp1->astOperand2();
// Comparison #2 (RHS)
const Token *comp2 = tok->astOperand2();
if (!comp1 || !comp1->isComparisonOp() || !comp1->astOperand1() || !comp1->astOperand2())
continue;
if (!comp2 || !comp2->isComparisonOp() || !comp2->astOperand1() || !comp2->astOperand2())
continue;
std::string op1, value1;
const Token *expr1;
if (comp1->astOperand1()->isLiteral()) {
op1 = invertOperatorForOperandSwap(comp1->str());
value1 = comp1->astOperand1()->str();
expr1 = comp1->astOperand2();
} else if (comp1->astOperand2()->isLiteral()) {
op1 = comp1->str();
value1 = comp1->astOperand2()->str();
expr1 = comp1->astOperand1();
} else {
continue;
}
std::string op2, value2;
const Token *expr2;
if (comp2->astOperand1()->isLiteral()) {
op2 = invertOperatorForOperandSwap(comp2->str());
value2 = comp2->astOperand1()->str();
expr2 = comp2->astOperand2();
} else if (comp2->astOperand2()->isLiteral()) {
op2 = comp2->str();
value2 = comp2->astOperand2()->str();
expr2 = comp2->astOperand1();
} else {
continue;
}
// Only float and int values are currently handled
if (!MathLib::isInt(value1) && !MathLib::isFloat(value1))
continue;
if (!MathLib::isInt(value2) && !MathLib::isFloat(value2))
continue;
const std::set<std::string> constStandardFunctions;
if (isSameExpression(comp1, comp2, constStandardFunctions))
continue; // same expressions => only report that there are same expressions
if (!isSameExpression(expr1, expr2, constStandardFunctions))
continue;
const bool isfloat = MathLib::isFloat(value1) || MathLib::isFloat(value2);
// don't check floating point equality comparisons. that is bad
// and deserves different warnings.
if (isfloat && (op1=="==" || op1=="!=" || op2=="==" || op2=="!="))
continue;
// evaluate if expression is always true/false
bool alwaysTrue = true, alwaysFalse = true;
bool firstTrue = true, secondTrue = true;
for (int test = 1; test <= 5; ++test) {
// test:
// 1 => testvalue is less than both value1 and value2
// 2 => testvalue is value1
// 3 => testvalue is between value1 and value2
// 4 => testvalue value2
// 5 => testvalue is larger than both value1 and value2
bool result1, result2;
if (isfloat) {
const double d1 = MathLib::toDoubleNumber(value1);
const double d2 = MathLib::toDoubleNumber(value2);
const double testvalue = getvalue<double>(test, d1, d2);
result1 = checkFloatRelation(op1, testvalue, d1);
result2 = checkFloatRelation(op2, testvalue, d2);
} else {
const MathLib::bigint i1 = MathLib::toLongNumber(value1);
const MathLib::bigint i2 = MathLib::toLongNumber(value2);
const MathLib::bigint testvalue = getvalue<MathLib::bigint>(test, i1, i2);
result1 = checkIntRelation(op1, testvalue, i1);
result2 = checkIntRelation(op2, testvalue, i2);
}
if (tok->str() == "&&") {
alwaysTrue &= (result1 && result2);
alwaysFalse &= !(result1 && result2);
} else {
alwaysTrue &= (result1 || result2);
alwaysFalse &= !(result1 || result2);
}
firstTrue &= !(!result1 && result2);
secondTrue &= !(result1 && !result2);
}
const std::string cond1str = (expr1->isName() ? expr1->str() : "EXPR") + " " + op1 + " " + value1;
const std::string cond2str = (expr2->isName() ? expr2->str() : "EXPR") + " " + op2 + " " + value2;
if (warning && (alwaysTrue || alwaysFalse)) {
const std::string text = cond1str + " " + tok->str() + " " + cond2str;
incorrectLogicOperatorError(tok, text, alwaysTrue);
} else if (style && secondTrue) {
const std::string text = "If " + cond1str + ", the comparison " + cond2str +
" is always " + (secondTrue ? "true" : "false") + ".";
redundantConditionError(tok, text);
} else if (style && firstTrue) {
//const std::string text = "The comparison " + cond1str + " is always " +
// (firstTrue ? "true" : "false") + " when " +
// cond2str + ".";
const std::string text = "If " + cond2str + ", the comparison " + cond1str +
" is always " + (firstTrue ? "true" : "false") + ".";
redundantConditionError(tok, text);
}
}
}
continue;
}
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
// Find a pair of comparison expressions with or without parentheses if (Token::Match(tok, "&&|%oror%")) {
// with a shared variable and constants and with a logical operator between them. // Comparison #1 (LHS)
// e.g. if (x != 3 || x != 4) const Token *comp1 = tok->astOperand1();
const Token *term1Tok = NULL, *term2Tok = NULL; if (comp1 && comp1->str() == tok->str())
const Token *op1Tok = NULL, *op2Tok = NULL, *op3Tok = NULL, *nextTok = NULL; comp1 = comp1->astOperand2();
if (Token::Match(tok, "( %any% %comp% %any% ) &&|%oror%")) { // Comparison #2 (RHS)
term1Tok = tok->next(); const Token *comp2 = tok->astOperand2();
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) { if (!comp1 || !comp1->isComparisonOp() || !comp1->astOperand1() || !comp1->astOperand2())
// Find the common variable and the two different-valued constants continue;
std::string firstConstant, secondConstant; if (!comp2 || !comp2->isComparisonOp() || !comp2->astOperand1() || !comp2->astOperand2())
bool varFirst1, varFirst2; continue;
unsigned int varId;
const Token *var1Tok = NULL, *var2Tok = NULL; std::string op1, value1;
if (Token::Match(term1Tok, "%var% %any% %num%")) { const Token *expr1;
var1Tok = term1Tok; if (comp1->astOperand1()->isLiteral()) {
varId = var1Tok->varId(); op1 = invertOperatorForOperandSwap(comp1->str());
if (!varId) { value1 = comp1->astOperand1()->str();
continue; expr1 = comp1->astOperand2();
} } else if (comp1->astOperand2()->isLiteral()) {
varFirst1 = true; op1 = comp1->str();
firstConstant = term1Tok->strAt(2); value1 = comp1->astOperand2()->str();
} else if (Token::Match(term1Tok, "%num% %any% %var%")) { expr1 = comp1->astOperand1();
var1Tok = term1Tok->tokAt(2);
varId = var1Tok->varId();
if (!varId) {
continue;
}
varFirst1 = false;
firstConstant = term1Tok->str();
} else { } else {
continue; continue;
} }
if (Token::Match(term2Tok, "%var% %any% %num%")) { std::string op2, value2;
var2Tok = term2Tok; const Token *expr2;
varFirst2 = true; if (comp2->astOperand1()->isLiteral()) {
secondConstant = term2Tok->strAt(2); op2 = invertOperatorForOperandSwap(comp2->str());
} else if (Token::Match(term2Tok, "%num% %any% %var%")) { value2 = comp2->astOperand1()->str();
var2Tok = term2Tok->tokAt(2); expr2 = comp2->astOperand2();
varFirst2 = false; } else if (comp2->astOperand2()->isLiteral()) {
secondConstant = term2Tok->str(); op2 = comp2->str();
value2 = comp2->astOperand2()->str();
expr2 = comp2->astOperand1();
} else { } else {
continue; continue;
} }
if (varId != var2Tok->varId() || firstConstant.empty() || secondConstant.empty()) { // Only float and int values are currently handled
if (!MathLib::isInt(value1) && !MathLib::isFloat(value1))
continue; continue;
if (!MathLib::isInt(value2) && !MathLib::isFloat(value2))
continue;
const std::set<std::string> constStandardFunctions;
if (isSameExpression(comp1, comp2, constStandardFunctions))
continue; // same expressions => only report that there are same expressions
if (!isSameExpression(expr1, expr2, constStandardFunctions))
continue;
const bool isfloat = MathLib::isFloat(value1) || MathLib::isFloat(value2);
// don't check floating point equality comparisons. that is bad
// and deserves different warnings.
if (isfloat && (op1=="==" || op1=="!=" || op2=="==" || op2=="!="))
continue;
// evaluate if expression is always true/false
bool alwaysTrue = true, alwaysFalse = true;
bool firstTrue = true, secondTrue = true;
for (int test = 1; test <= 5; ++test) {
// test:
// 1 => testvalue is less than both value1 and value2
// 2 => testvalue is value1
// 3 => testvalue is between value1 and value2
// 4 => testvalue value2
// 5 => testvalue is larger than both value1 and value2
bool result1, result2;
if (isfloat) {
const double d1 = MathLib::toDoubleNumber(value1);
const double d2 = MathLib::toDoubleNumber(value2);
const double testvalue = getvalue<double>(test, d1, d2);
result1 = checkFloatRelation(op1, testvalue, d1);
result2 = checkFloatRelation(op2, testvalue, d2);
} else {
const MathLib::bigint i1 = MathLib::toLongNumber(value1);
const MathLib::bigint i2 = MathLib::toLongNumber(value2);
const MathLib::bigint testvalue = getvalue<MathLib::bigint>(test, i1, i2);
result1 = checkIntRelation(op1, testvalue, i1);
result2 = checkIntRelation(op2, testvalue, i2);
}
if (tok->str() == "&&") {
alwaysTrue &= (result1 && result2);
alwaysFalse &= !(result1 && result2);
} else {
alwaysTrue &= (result1 || result2);
alwaysFalse &= !(result1 || result2);
}
firstTrue &= !(!result1 && result2);
secondTrue &= !(result1 && !result2);
} }
enum LogicError { AlwaysFalse, AlwaysTrue, FirstTrue, FirstFalse, SecondTrue, SecondFalse }; const std::string cond1str = (expr1->isName() ? expr1->str() : "EXPR") + " " + op1 + " " + value1;
const std::string cond2str = (expr2->isName() ? expr2->str() : "EXPR") + " " + op2 + " " + value2;
static const struct LinkedConditions { if (warning && (alwaysTrue || alwaysFalse)) {
const char *before; const std::string text = cond1str + " " + tok->str() + " " + cond2str;
Condition c1; incorrectLogicOperatorError(tok, text, alwaysTrue);
const char *op2TokStr; } else if (style && secondTrue) {
Condition c2; const std::string text = "If " + cond1str + ", the comparison " + cond2str +
const char *after; " is always " + (secondTrue ? "true" : "false") + ".";
Relation relation; redundantConditionError(tok, text);
LogicError error; } else if (style && firstTrue) {
} conditions[] = { //const std::string text = "The comparison " + cond1str + " is always " +
{ "!!&&", { NA, "!=" }, "%oror%", { NA, "!=" }, "!!&&", NotEqual, AlwaysTrue }, // (x != 1) || (x != 3) <- always true // (firstTrue ? "true" : "false") + " when " +
{ 0, { NA, "==" }, "&&", { NA, "==" }, 0, NotEqual, AlwaysFalse }, // (x == 1) && (x == 3) <- always false // cond2str + ".";
{ "!!&&", { First, ">" }, "%oror%", { First, "<" }, "!!&&", Less, AlwaysTrue }, // (x > 3) || (x < 10) <- always true const std::string text = "If " + cond2str + ", the comparison " + cond1str +
{ "!!&&", { First, ">=" }, "%oror%", { First, "<|<=" }, "!!&&", LessEqual, AlwaysTrue }, // (x >= 3) || (x < 10) <- always true " is always " + (firstTrue ? "true" : "false") + ".";
{ "!!&&", { First, ">" }, "%oror%", { First, "<=" }, "!!&&", LessEqual, AlwaysTrue }, // (x > 3) || (x <= 10) <- always true redundantConditionError(tok, text);
{ 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,57 +3156,18 @@ void CheckOther::checkDuplicateExpression()
if (scope->type != Scope::eFunction) if (scope->type != Scope::eFunction)
continue; continue;
if (_settings->ast) { std::set<std::string> constStandardFunctions;
std::set<std::string> constStandardFunctions; constStandardFunctions.insert("strcmp");
constStandardFunctions.insert("strcmp");
// Experimental implementation // Experimental implementation
for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) { for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) {
if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|-|*|/|%|=|<<|>>")) { if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|-|*|/|%|=|<<|>>")) {
if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1())) if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1()))
continue;
if (isSameExpression(tok->astOperand1(), tok->astOperand2(), constStandardFunctions))
duplicateExpressionError(tok, tok, tok->str());
else if (tok->astOperand1() && tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(tok->astOperand2(), tok->astOperand1()->astOperand2(), constStandardFunctions))
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; continue;
if (isSameExpression(tok->astOperand1(), tok->astOperand2(), constStandardFunctions))
duplicateExpressionError(tok->next(), tok->tokAt(3), tok->strAt(2)); duplicateExpressionError(tok, tok, tok->str());
} else if (Token::Match(tok, ",|=|return|(|&&|%oror% %var% . %var% %comp%|- %var% . %var% )|&&|%oror%|;|,") && else if (tok->astOperand1() && tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(tok->astOperand2(), tok->astOperand1()->astOperand2(), constStandardFunctions))
tok->strAt(1) == tok->strAt(5) && tok->strAt(3) == tok->strAt(7)) { duplicateExpressionError(tok->astOperand2(), tok->astOperand2(), tok->str());
// 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() Settings::Settings()
: _terminate(false), : _terminate(false),
debug(false), debugwarnings(false), debugFalsePositive(false), debug(false), debugwarnings(false), debugFalsePositive(false),
ast(false), inconclusive(false), experimental(false), inconclusive(false), experimental(false),
_errorsOnly(false), _errorsOnly(false),
_inlineSuppressions(false), _inlineSuppressions(false),
_verbose(false), _verbose(false),

View File

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

View File

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

View File

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

View File

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