bool astIsIntegral(const Token *tok, bool unknown) { // TODO: handle arrays if (tok->isNumber()) return MathLib::isInt(tok->str()); if (tok->isName()) { if (tok->variable()) return tok->variable()->isIntegralType(); return unknown; } if (tok->str() == "(") { // cast if (Token::Match(tok, "( const| float|double )")) return false; // Function call if (tok->previous()->function()) { if (Token::Match(tok->previous()->function()->retDef, "float|double")) return false; else if (Token::Match(tok->previous()->function()->retDef, "bool|char|short|int|long")) return true; } if (tok->strAt(-1) == "sizeof") return true; return unknown; } if (tok->astOperand2() && (tok->str() == "." || tok->str() == "::")) return astIsIntegral(tok->astOperand2(), unknown); if (tok->astOperand1() && tok->str() != "?") return astIsIntegral(tok->astOperand1(), unknown); return unknown; }
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions) { if (tok1 == nullptr && tok2 == nullptr) return true; if (tok1 == nullptr || tok2 == nullptr) return false; if (cpp) { if (tok1->str() == "." && tok1->astOperand1() && tok1->astOperand1()->str() == "this") tok1 = tok1->astOperand2(); if (tok2->str() == "." && tok2->astOperand1() && tok2->astOperand1()->str() == "this") tok2 = tok2->astOperand2(); } if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->originalName() != tok2->originalName()) { if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) || (Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) { return isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions) && isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions); } return false; } if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro())) return false; if (tok1->isName() && tok1->next()->str() == "(" && tok1->str() != "sizeof") { if (!tok1->function() && !Token::Match(tok1->previous(), ".|::") && constFunctions.find(tok1->str()) == constFunctions.end() && !tok1->isAttributeConst() && !tok1->isAttributePure()) return false; else if (tok1->function() && !tok1->function()->isConst() && !tok1->function()->isAttributeConst() && !tok1->function()->isAttributePure()) return false; } // templates/casts if ((Token::Match(tok1, "%name% <") && tok1->next()->link()) || (Token::Match(tok2, "%name% <") && tok2->next()->link())) { // non-const template function that is not a dynamic_cast => return false if (Token::simpleMatch(tok1->next()->link(), "> (") && !(tok1->function() && tok1->function()->isConst()) && tok1->str() != "dynamic_cast") return false; // some template/cast stuff.. check that the template arguments are same const Token *t1 = tok1->next(); const Token *t2 = tok2->next(); const Token *end1 = t1->link(); const Token *end2 = t2->link(); while (t1 && t2 && t1 != end1 && t2 != end2) { if (t1->str() != t2->str()) return false; t1 = t1->next(); t2 = t2->next(); } if (t1 != end1 || t2 != end2) return false; } if (tok1->tokType() == Token::eIncDecOp || tok1->isAssignmentOp()) return false; // bailout when we see ({..}) if (tok1->str() == "{") return false; if (tok1->str() == "(" && tok1->previous() && !tok1->previous()->isName()) { // cast => assert that the casts are equal const Token *t1 = tok1->next(); const Token *t2 = tok2->next(); while (t1 && t2 && t1->str() == t2->str() && (t1->isName() || t1->str() == "*")) { t1 = t1->next(); t2 = t2->next(); } if (!t1 || !t2 || t1->str() != ")" || t2->str() != ")") return false; } bool noncommuative_equals = isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), constFunctions); noncommuative_equals = noncommuative_equals && isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), constFunctions); if (noncommuative_equals) return true; const bool commutative = tok1->astOperand1() && tok1->astOperand2() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!="); bool commuative_equals = commutative && isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions); commuative_equals = commuative_equals && isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions); // in c++, "a"+b might be different to b+"a" if (cpp && commuative_equals && tok1->str() == "+" && (tok1->astOperand1()->tokType() == Token::eString || tok1->astOperand2()->tokType() == Token::eString)) { const Token * const other = tok1->astOperand1()->tokType() != Token::eString ? tok1->astOperand1() : tok1->astOperand2(); return other && astIsIntegral(other,false); } return commuative_equals; }