Moved functions to astutils

This commit is contained in:
Daniel Marjamäki 2015-08-03 09:20:50 +02:00
parent b8bb939e32
commit e598b07a6d
12 changed files with 286 additions and 271 deletions

View File

@ -283,7 +283,7 @@ endif
###### Build
$(SRCDIR)/astutils.o: lib/astutils.cpp lib/cxx11emu.h lib/astutils.h lib/symboldatabase.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/utils.h
$(SRCDIR)/astutils.o: lib/astutils.cpp lib/cxx11emu.h lib/astutils.h lib/symboldatabase.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/utils.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/astutils.o $(SRCDIR)/astutils.cpp
$(SRCDIR)/check.o: lib/check.cpp lib/cxx11emu.h lib/check.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h
@ -310,7 +310,7 @@ $(SRCDIR)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp lib/cxx11emu.h lib/ch
$(SRCDIR)/checkclass.o: lib/checkclass.cpp lib/cxx11emu.h lib/checkclass.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkclass.o $(SRCDIR)/checkclass.cpp
$(SRCDIR)/checkcondition.o: lib/checkcondition.cpp lib/cxx11emu.h lib/checkcondition.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/astutils.h lib/symboldatabase.h lib/utils.h lib/checkother.h
$(SRCDIR)/checkcondition.o: lib/checkcondition.cpp lib/cxx11emu.h lib/checkcondition.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/astutils.h lib/checkother.h lib/symboldatabase.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkcondition.o $(SRCDIR)/checkcondition.cpp
$(SRCDIR)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/cxx11emu.h lib/checkexceptionsafety.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
@ -322,10 +322,10 @@ $(SRCDIR)/checkinternal.o: lib/checkinternal.cpp lib/cxx11emu.h lib/checkinterna
$(SRCDIR)/checkio.o: lib/checkio.cpp lib/cxx11emu.h lib/checkio.h lib/check.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkio.o $(SRCDIR)/checkio.cpp
$(SRCDIR)/checkleakautovar.o: lib/checkleakautovar.cpp lib/cxx11emu.h lib/checkleakautovar.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/checkmemoryleak.h lib/symboldatabase.h lib/utils.h
$(SRCDIR)/checkleakautovar.o: lib/checkleakautovar.cpp lib/cxx11emu.h lib/checkleakautovar.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/checkmemoryleak.h lib/symboldatabase.h lib/utils.h lib/astutils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkleakautovar.o $(SRCDIR)/checkleakautovar.cpp
$(SRCDIR)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/cxx11emu.h lib/checkmemoryleak.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
$(SRCDIR)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/cxx11emu.h lib/checkmemoryleak.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h lib/astutils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkmemoryleak.o $(SRCDIR)/checkmemoryleak.cpp
$(SRCDIR)/checknonreentrantfunctions.o: lib/checknonreentrantfunctions.cpp lib/cxx11emu.h lib/checknonreentrantfunctions.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
@ -355,7 +355,7 @@ $(SRCDIR)/checkstring.o: lib/checkstring.cpp lib/cxx11emu.h lib/checkstring.h li
$(SRCDIR)/checktype.o: lib/checktype.cpp lib/cxx11emu.h lib/checktype.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checktype.o $(SRCDIR)/checktype.cpp
$(SRCDIR)/checkuninitvar.o: lib/checkuninitvar.cpp lib/cxx11emu.h lib/checkuninitvar.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/checknullpointer.h lib/symboldatabase.h lib/utils.h
$(SRCDIR)/checkuninitvar.o: lib/checkuninitvar.cpp lib/cxx11emu.h lib/checkuninitvar.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/astutils.h lib/checknullpointer.h lib/symboldatabase.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkuninitvar.o $(SRCDIR)/checkuninitvar.cpp
$(SRCDIR)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp lib/cxx11emu.h lib/checkunusedfunctions.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h

View File

@ -19,6 +19,36 @@
//---------------------------------------------------------------------------
#include "astutils.h"
#include "symboldatabase.h"
#include "token.h"
#include "tokenize.h"
#include <set>
static bool isChar(const Variable* var)
{
return (var && !var->isPointer() && !var->isArray() && var->typeStartToken()->str() == "char");
}
static bool isSignedChar(const Variable* var)
{
return (isChar(var) && !var->typeStartToken()->isUnsigned());
}
bool astIsSignedChar(const Token *tok)
{
if (!tok)
return false;
if (tok->str() == "*" && tok->astOperand1() && !tok->astOperand2()) {
const Variable *var = tok->astOperand1()->variable();
if (!var || !var->isPointer())
return false;
const Token *type = var->typeStartToken();
while (type && type->str() == "const")
type = type->next();
return (type && type->str() == "char" && !type->isUnsigned());
}
return isSignedChar(tok->variable());
}
bool astIsIntegral(const Token *tok, bool unknown)
{
@ -100,3 +130,205 @@ bool astIsFloat(const Token *tok, bool unknown)
return unknown;
}
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok)
{
if (!tok)
return nullptr;
const Token *ret = nullptr;
if (tok->isComparisonOp()) {
if (tok->astOperand1() && tok->astOperand1()->str() == rhs) {
// Invert comparator
std::string s = tok->str();
if (s[0] == '>')
s[0] = '<';
else if (s[0] == '<')
s[0] = '>';
if (s == comp) {
ret = tok->astOperand2();
}
} else if (tok->str() == comp && tok->astOperand2() && tok->astOperand2()->str() == rhs) {
ret = tok->astOperand1();
}
} else if (comp == "!=" && rhs == std::string("0")) {
ret = tok;
} else if (comp == "==" && rhs == std::string("0")) {
if (tok->str() == "!")
ret = tok->astOperand1();
}
while (ret && ret->str() == ".")
ret = ret->astOperand2();
if (ret && ret->varId() == 0U)
ret = nullptr;
if (vartok)
*vartok = ret;
return ret;
}
bool isSameExpression(bool cpp, 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()) {
if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
(Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
return isSameExpression(cpp, tok1->astOperand1(), tok2->astOperand2(), constFunctions) &&
isSameExpression(cpp, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
}
return false;
}
if (tok1->str() == "." && tok1->originalName() != tok2->originalName())
return false;
if (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->type() == 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, tok1->astOperand1(), tok2->astOperand1(), constFunctions);
noncommuative_equals = noncommuative_equals &&
isSameExpression(cpp, 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, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
commuative_equals = commuative_equals &&
isSameExpression(cpp, tok1->astOperand1(), tok2->astOperand2(), constFunctions);
return commuative_equals;
}
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions)
{
if (!cond1 || !cond2)
return false;
if (cond1->str() == "!") {
if (cond2->str() == "!=") {
if (cond2->astOperand1() && cond2->astOperand1()->str() == "0")
return isSameExpression(cpp, cond1->astOperand1(), cond2->astOperand2(), constFunctions);
if (cond2->astOperand2() && cond2->astOperand2()->str() == "0")
return isSameExpression(cpp, cond1->astOperand1(), cond2->astOperand1(), constFunctions);
}
return isSameExpression(cpp, cond1->astOperand1(), cond2, constFunctions);
}
if (cond2->str() == "!")
return isOppositeCond(isNot, cpp, cond2, cond1, constFunctions);
if (!cond1->isComparisonOp() || !cond2->isComparisonOp())
return false;
const std::string &comp1 = cond1->str();
// condition found .. get comparator
std::string comp2;
if (isSameExpression(cpp, cond1->astOperand1(), cond2->astOperand1(), constFunctions) &&
isSameExpression(cpp, cond1->astOperand2(), cond2->astOperand2(), constFunctions)) {
comp2 = cond2->str();
} else if (isSameExpression(cpp, cond1->astOperand1(), cond2->astOperand2(), constFunctions) &&
isSameExpression(cpp, cond1->astOperand2(), cond2->astOperand1(), constFunctions)) {
comp2 = cond2->str();
if (comp2[0] == '>')
comp2[0] = '<';
else if (comp2[0] == '<')
comp2[0] = '>';
}
// is condition opposite?
return ((comp1 == "==" && comp2 == "!=") ||
(comp1 == "!=" && comp2 == "==") ||
(comp1 == "<" && comp2 == ">=") ||
(comp1 == "<=" && comp2 == ">") ||
(comp1 == ">" && comp2 == "<=") ||
(comp1 == ">=" && comp2 == "<") ||
(!isNot && ((comp1 == "<" && comp2 == ">") ||
(comp1 == ">" && comp2 == "<"))));
}
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions)
{
if (!tok)
return true;
if (tok->isName() && tok->next()->str() == "(") {
if (!tok->function() && !Token::Match(tok->previous(), ".|::") && constFunctions.find(tok->str()) == constFunctions.end())
return false;
else if (tok->function() && !tok->function()->isConst())
return false;
}
if (tok->type() == Token::eIncDecOp)
return false;
// bailout when we see ({..})
if (tok->str() == "{")
return false;
return isConstExpression(tok->astOperand1(),constFunctions) && isConstExpression(tok->astOperand2(),constFunctions);
}
bool isWithoutSideEffects(bool cpp, const Token* tok)
{
if (!cpp)
return true;
while (tok && tok->astOperand2() && tok->astOperand2()->str() != "(")
tok = tok->astOperand2();
if (tok && tok->varId()) {
const Variable* var = tok->variable();
return var && (!var->isClass() || var->isPointer() || var->isStlType());
}
return true;
}

View File

@ -22,12 +22,35 @@
#define astutilsH
//---------------------------------------------------------------------------
#include "symboldatabase.h"
#include "token.h"
#include <set>
#include <string>
class Token;
class Tokenizer;
/** Is expression a 'signed char' if no promotion is used */
bool astIsSignedChar(const Token *tok);
/** Is expression of integral type? */
bool astIsIntegral(const Token *tok, bool unknown);
/** Is expression of floating point type? */
bool astIsFloat(const Token *tok, bool unknown);
/** Is given syntax tree a variable comparison against value */
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
bool isSameExpression(bool cpp, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions);
/**
* Are two conditions opposite
* @param isNot do you want to know if cond1 is !cond2 or if cond1 and cond2 are non-overlapping. true: cond1==!cond2 false: cond1==true => cond2==false
* @param cpp c++ file
* @param cond1 condition1
* @param cond2 condition2
*/
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions);
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions);
bool isWithoutSideEffects(bool cpp, const Token* tok);
#endif // astutilsH

View File

@ -301,7 +301,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token *
return false;
// same expressions
if (isSameExpression(_tokenizer, cond1,cond2,constFunctions))
if (isSameExpression(_tokenizer->isCPP(), cond1,cond2,constFunctions))
return true;
// bitwise overlap for example 'x&7' and 'x==1'
@ -324,7 +324,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token *
if (!num2->isNumber() || MathLib::isNegative(num2->str()))
return false;
if (!isSameExpression(_tokenizer, expr1,expr2,constFunctions))
if (!isSameExpression(_tokenizer->isCPP(), expr1,expr2,constFunctions))
return false;
const MathLib::bigint value1 = MathLib::toLongNumber(num1->str());
@ -377,54 +377,6 @@ void CheckCondition::multiConditionError(const Token *tok, unsigned int line1)
// Detect oppositing inner and outer conditions
//---------------------------------------------------------------------------
bool CheckCondition::isOppositeCond(bool isNot, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const
{
if (!cond1 || !cond2)
return false;
if (cond1->str() == "!") {
if (cond2->str() == "!=") {
if (cond2->astOperand1() && cond2->astOperand1()->str() == "0")
return isSameExpression(_tokenizer, cond1->astOperand1(), cond2->astOperand2(), constFunctions);
if (cond2->astOperand2() && cond2->astOperand2()->str() == "0")
return isSameExpression(_tokenizer, cond1->astOperand1(), cond2->astOperand1(), constFunctions);
}
return isSameExpression(_tokenizer, cond1->astOperand1(), cond2, constFunctions);
}
if (cond2->str() == "!")
return isOppositeCond(isNot, cond2, cond1, constFunctions);
if (!cond1->isComparisonOp() || !cond2->isComparisonOp())
return false;
const std::string &comp1 = cond1->str();
// condition found .. get comparator
std::string comp2;
if (isSameExpression(_tokenizer, cond1->astOperand1(), cond2->astOperand1(), constFunctions) &&
isSameExpression(_tokenizer, cond1->astOperand2(), cond2->astOperand2(), constFunctions)) {
comp2 = cond2->str();
} else if (isSameExpression(_tokenizer, cond1->astOperand1(), cond2->astOperand2(), constFunctions) &&
isSameExpression(_tokenizer, cond1->astOperand2(), cond2->astOperand1(), constFunctions)) {
comp2 = cond2->str();
if (comp2[0] == '>')
comp2[0] = '<';
else if (comp2[0] == '<')
comp2[0] = '>';
}
// is condition opposite?
return ((comp1 == "==" && comp2 == "!=") ||
(comp1 == "!=" && comp2 == "==") ||
(comp1 == "<" && comp2 == ">=") ||
(comp1 == "<=" && comp2 == ">") ||
(comp1 == ">" && comp2 == "<=") ||
(comp1 == ">=" && comp2 == "<") ||
(!isNot && ((comp1 == "<" && comp2 == ">") ||
(comp1 == ">" && comp2 == "<"))));
}
void CheckCondition::oppositeInnerCondition()
{
if (!_settings->isEnabled("warning"))
@ -494,7 +446,7 @@ void CheckCondition::oppositeInnerCondition()
const Token *cond1 = scope->classDef->next()->astOperand2();
const Token *cond2 = ifToken->next()->astOperand2();
if (isOppositeCond(false, cond1, cond2, _settings->library.functionpure))
if (isOppositeCond(false, _tokenizer->isCPP(), cond1, cond2, _settings->library.functionpure))
oppositeInnerConditionError(scope->classDef, cond2);
}
}
@ -682,7 +634,7 @@ void CheckCondition::checkIncorrectLogicOperator()
// Opposite comparisons around || or && => always true or always false
if ((tok->astOperand1()->isName() || tok->astOperand2()->isName()) &&
isOppositeCond(true, tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
const bool alwaysTrue(tok->str() == "||");
incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue);
@ -693,7 +645,7 @@ void CheckCondition::checkIncorrectLogicOperator()
// 'A && (!A || B)' is equivalent with 'A || B'
if (printStyle && (tok->str() == "||") && tok->astOperand1() && tok->astOperand2() && tok->astOperand2()->str() == "&&") {
const Token* tok2 = tok->astOperand2()->astOperand1();
if (isOppositeCond(true, tok->astOperand1(), tok2, _settings->library.functionpure)) {
if (isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok2, _settings->library.functionpure)) {
redundantConditionError(tok, tok2->expressionString() + ". 'A && (!A || B)' is equivalent to 'A || B'");
continue;
}
@ -721,9 +673,9 @@ void CheckCondition::checkIncorrectLogicOperator()
if (!parseComparison(comp2, &not2, &op2, &value2, &expr2))
continue;
if (isSameExpression(_tokenizer, comp1, comp2, _settings->library.functionpure))
if (isSameExpression(_tokenizer->isCPP(), comp1, comp2, _settings->library.functionpure))
continue; // same expressions => only report that there are same expressions
if (!isSameExpression(_tokenizer, expr1, expr2, _settings->library.functionpure))
if (!isSameExpression(_tokenizer->isCPP(), expr1, expr2, _settings->library.functionpure))
continue;
const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2);

View File

@ -100,13 +100,6 @@ public:
private:
bool isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const;
/**
* Are two conditions opposite
* @param isNot do you want to know if cond1 is !cond2 or if cond1 and cond2 are non-overlapping. true: cond1==!cond2 false: cond1==true => cond2==false
* @param cond1 condition1
* @param cond2 condition2
*/
bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const;
void assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result);
void mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2);
void badBitmaskCheckError(const Token *tok);

View File

@ -24,6 +24,7 @@
#include "checkmemoryleak.h" // <- CheckMemoryLeak::memoryLeak
#include "tokenize.h"
#include "symboldatabase.h"
#include "astutils.h"
#include <iostream>
#include <stack>
@ -307,17 +308,17 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
}
const Token *vartok = nullptr;
if (Token::isVariableComparison(tok3, "!=", "0", &vartok)) {
if (astIsVariableComparison(tok3, "!=", "0", &vartok)) {
varInfo2.erase(vartok->varId());
if (notzero.find(vartok->varId()) != notzero.end())
varInfo2.clear();
} else if (Token::isVariableComparison(tok3, "==", "0", &vartok)) {
} else if (astIsVariableComparison(tok3, "==", "0", &vartok)) {
varInfo1.erase(vartok->varId());
} else if (Token::isVariableComparison(tok3, "<", "0", &vartok)) {
} else if (astIsVariableComparison(tok3, "<", "0", &vartok)) {
varInfo1.erase(vartok->varId());
} else if (Token::isVariableComparison(tok3, ">", "0", &vartok)) {
} else if (astIsVariableComparison(tok3, ">", "0", &vartok)) {
varInfo2.erase(vartok->varId());
} else if (Token::isVariableComparison(tok3, "==", "-1", &vartok)) {
} else if (astIsVariableComparison(tok3, "==", "-1", &vartok)) {
varInfo1.erase(vartok->varId());
}
}

View File

@ -21,6 +21,7 @@
#include "symboldatabase.h"
#include "mathlib.h"
#include "tokenize.h"
#include "astutils.h"
#include <algorithm>
#include <sstream>
@ -525,7 +526,7 @@ static bool notvar(const Token *tok, unsigned int varid)
return notvar(tok->astOperand1(),varid) || notvar(tok->astOperand2(),varid);
if (tok->str() == "(" && Token::Match(tok->astOperand1(), "UNLIKELY|LIKELY"))
return notvar(tok->astOperand2(), varid);
const Token *vartok = Token::isVariableComparison(tok, "==", "0");
const Token *vartok = astIsVariableComparison(tok, "==", "0");
return vartok && (vartok->varId() == varid);
}
@ -539,7 +540,7 @@ static bool ifvar(const Token *tok, unsigned int varid, const std::string &comp,
if (!condition || condition->str() == "&&")
return false;
const Token *vartok = Token::isVariableComparison(condition, comp, rhs);
const Token *vartok = astIsVariableComparison(condition, comp, rhs);
return (vartok && vartok->varId() == varid);
}

View File

@ -34,109 +34,6 @@ namespace {
}
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions)
{
if (!tok)
return true;
if (tok->isName() && tok->next()->str() == "(") {
if (!tok->function() && !Token::Match(tok->previous(), ".|::") && constFunctions.find(tok->str()) == constFunctions.end())
return false;
else if (tok->function() && !tok->function()->isConst())
return false;
}
if (tok->type() == Token::eIncDecOp)
return false;
// bailout when we see ({..})
if (tok->str() == "{")
return false;
return isConstExpression(tok->astOperand1(),constFunctions) && isConstExpression(tok->astOperand2(),constFunctions);
}
bool isSameExpression(const Tokenizer *tokenizer, 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 (tokenizer->isCPP()) {
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()) {
if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
(Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
return isSameExpression(tokenizer, tok1->astOperand1(), tok2->astOperand2(), constFunctions) &&
isSameExpression(tokenizer, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
}
return false;
}
if (tok1->str() == "." && tok1->originalName() != tok2->originalName())
return false;
if (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->type() == 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(tokenizer, tok1->astOperand1(), tok2->astOperand1(), constFunctions);
noncommuative_equals = noncommuative_equals &&
isSameExpression(tokenizer, 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(tokenizer, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
commuative_equals = commuative_equals &&
isSameExpression(tokenizer, tok1->astOperand1(), tok2->astOperand2(), constFunctions);
return commuative_equals;
}
//----------------------------------------------------------------------------------
// The return value of fgetc(), getc(), ungetc(), getchar() etc. is an integer value.
@ -1572,31 +1469,6 @@ void CheckOther::passedByValueError(const Token *tok, const std::string &parname
//---------------------------------------------------------------------------
// Check usage of char variables..
//---------------------------------------------------------------------------
static bool isChar(const Variable* var)
{
return (var && !var->isPointer() && !var->isArray() && var->typeStartToken()->str() == "char");
}
static bool isSignedChar(const Variable* var)
{
return (isChar(var) && !var->typeStartToken()->isUnsigned());
}
static bool astIsSignedChar(const Token *tok)
{
if (!tok)
return false;
if (tok->str() == "*" && tok->astOperand1() && !tok->astOperand2()) {
const Variable *var = tok->astOperand1()->variable();
if (!var || !var->isPointer())
return false;
const Token *type = var->typeStartToken();
while (type && type->str() == "const")
type = type->next();
return (type && type->str() == "char" && !type->isUnsigned());
}
return isSignedChar(tok->variable());
}
void CheckOther::checkCharVariable()
{
@ -2134,20 +2006,6 @@ namespace {
}
}
bool isWithoutSideEffects(const Tokenizer *tokenizer, const Token* tok)
{
if (!tokenizer->isCPP())
return true;
while (tok && tok->astOperand2() && tok->astOperand2()->str() != "(")
tok = tok->astOperand2();
if (tok && tok->varId()) {
const Variable* var = tok->variable();
return var && (!var->isClass() || var->isPointer() || var->isStlType());
}
return true;
}
void CheckOther::checkDuplicateExpression()
{
if (!_settings->isEnabled("style"))
@ -2170,8 +2028,8 @@ void CheckOther::checkDuplicateExpression()
if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|*|<<|>>")) {
if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1(), true))
continue;
if (isSameExpression(_tokenizer, tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
if (isWithoutSideEffects(_tokenizer, tok->astOperand1())) {
if (isSameExpression(_tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
if (isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand1())) {
const bool assignment = tok->str() == "=";
if (assignment)
selfAssignmentError(tok, tok->astOperand1()->expressionString());
@ -2189,16 +2047,16 @@ void CheckOther::checkDuplicateExpression()
}
}
} else if (!Token::Match(tok, "[-/%]")) { // These operators are not associative
if (tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(_tokenizer, tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, tok->astOperand2()))
if (tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(_tokenizer->isCPP(), tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand2()))
duplicateExpressionError(tok->astOperand2(), tok->astOperand2(), tok->str());
else if (tok->astOperand2()) {
const Token *ast1 = tok->astOperand1();
while (ast1 && tok->str() == ast1->str()) {
if (isSameExpression(_tokenizer, ast1->astOperand1(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, ast1->astOperand1()))
if (isSameExpression(_tokenizer->isCPP(), ast1->astOperand1(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand1()))
// TODO: warn if variables are unchanged. See #5683
// Probably the message should be changed to 'duplicate expressions X in condition or something like that'.
;//duplicateExpressionError(ast1->astOperand1(), tok->astOperand2(), tok->str());
else if (isSameExpression(_tokenizer, ast1->astOperand2(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, ast1->astOperand2()))
else if (isSameExpression(_tokenizer->isCPP(), ast1->astOperand2(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand2()))
duplicateExpressionError(ast1->astOperand2(), tok->astOperand2(), tok->str());
if (!isConstExpression(ast1->astOperand2(), _settings->library.functionpure))
break;
@ -2207,7 +2065,7 @@ void CheckOther::checkDuplicateExpression()
}
}
} else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") {
if (isSameExpression(_tokenizer, tok->astOperand1(), tok->astOperand2(), temp))
if (isSameExpression(_tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), temp))
duplicateExpressionTernaryError(tok);
}
}

View File

@ -28,13 +28,6 @@
class Function;
class Variable;
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions);
/** Is expressions same? */
bool isSameExpression(const Tokenizer *tokenizer, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions);
bool isWithoutSideEffects(const Tokenizer *tokenizer, const Token* tok);
/// @addtogroup Checks
/// @{

View File

@ -19,6 +19,7 @@
//---------------------------------------------------------------------------
#include "checkuninitvar.h"
#include "astutils.h"
#include "mathlib.h"
#include "checknullpointer.h" // CheckNullPointer::parseFunctionCall
#include "symboldatabase.h"
@ -280,7 +281,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
unsigned int condVarId = 0, condVarValue = 0;
const Token *condVarTok = nullptr;
if (Token::simpleMatch(tok, "if (") &&
Token::isVariableComparison(tok->next()->astOperand2(), "!=", "0", &condVarTok)) {
astIsVariableComparison(tok->next()->astOperand2(), "!=", "0", &condVarTok)) {
std::map<unsigned int,int>::const_iterator it = variableValue.find(condVarTok->varId());
if (it != variableValue.end() && it->second == NOT_ZERO)
return true; // this scope is not fully analysed => return true

View File

@ -1468,42 +1468,6 @@ const Token *Token::getValueTokenDeadPointer() const
return nullptr;
}
const Token * Token::isVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok)
{
if (!tok)
return nullptr;
const Token *ret = nullptr;
if (tok->isComparisonOp()) {
if (tok->astOperand1() && tok->astOperand1()->str() == rhs) {
// Invert comparator
std::string s = tok->str();
if (s[0] == '>')
s[0] = '<';
else if (s[0] == '<')
s[0] = '>';
if (s == comp) {
ret = tok->astOperand2();
}
} else if (tok->str() == comp && tok->astOperand2() && tok->astOperand2()->str() == rhs) {
ret = tok->astOperand1();
}
} else if (comp == "!=" && rhs == std::string("0")) {
ret = tok;
} else if (comp == "==" && rhs == std::string("0")) {
if (tok->str() == "!")
ret = tok->astOperand1();
}
while (ret && ret->str() == ".")
ret = ret->astOperand2();
if (ret && ret->varId() == 0U)
ret = nullptr;
if (vartok)
*vartok = ret;
return ret;
}
void Token::assignProgressValues(Token *tok)
{
unsigned int total_count = 0;

View File

@ -717,9 +717,6 @@ public:
const Token *getValueTokenDeadPointer() const;
/** Is given syntax tree a variable comparison against value */
static const Token * isVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
private:
void next(Token *nextToken) {