diff --git a/lib/checkassignif.cpp b/lib/checkassignif.cpp index dea375b6e..1b42405db 100644 --- a/lib/checkassignif.cpp +++ b/lib/checkassignif.cpp @@ -79,13 +79,13 @@ bool CheckAssignIf::assignIfParseScope(const Token * const assignTok, const MathLib::bigint num) { for (const Token *tok2 = startTok; tok2; tok2 = tok2->next()) { - if (Token::Match(tok2->tokAt(2), "%varid% %op% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) { + if (Token::Match(tok2->tokAt(2), "%varid% %cop% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) { const MathLib::bigint num2 = MathLib::toLongNumber(tok2->strAt(4)); if ((bitop == '&') && (0 == (num & num2))) mismatchingBitAndError(assignTok, num, tok2, num2); } if (Token::Match(tok2, "%varid% =", varid)) { - if (Token::Match(tok2->tokAt(2), "%varid% %op% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) { + if (Token::Match(tok2->tokAt(2), "%varid% %cop% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) { const MathLib::bigint num2 = MathLib::toLongNumber(tok2->strAt(4)); if ((bitop == '&') && (0 == (num & num2))) mismatchingBitAndError(assignTok, num, tok2, num2); diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index b65f9acd9..3db2bc66a 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -669,7 +669,7 @@ void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int p Token::Match(ftok, "%var% --")) break; - if (Token::Match(ftok->previous(), "=|;|{|}|%op% %var% [ %num% ]")) { + if (Token::Match(ftok->previous(), ";|{|}|%op% %var% [ %num% ]")) { const MathLib::bigint index = MathLib::toLongNumber(ftok->strAt(2)); if (index >= 0 && arrayInfo.num(0) > 0 && index >= arrayInfo.num(0)) { std::list callstack2(callstack); diff --git a/lib/checkinternal.cpp b/lib/checkinternal.cpp index 58cd4019b..ca780cd07 100644 --- a/lib/checkinternal.cpp +++ b/lib/checkinternal.cpp @@ -127,6 +127,7 @@ void CheckInternal::checkMissingPercentCharacter() magics.insert("%comp%"); magics.insert("%num%"); magics.insert("%op%"); + magics.insert("%cop%"); magics.insert("%or%"); magics.insert("%oror%"); magics.insert("%str%"); @@ -182,6 +183,7 @@ void CheckInternal::checkUnknownPattern() knownPatterns.insert("%comp%"); knownPatterns.insert("%num%"); knownPatterns.insert("%op%"); + knownPatterns.insert("%cop%"); knownPatterns.insert("%or%"); knownPatterns.insert("%oror%"); knownPatterns.insert("%str%"); diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index e2b451a90..ddba8f9d1 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -1286,8 +1286,8 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::listprevious(), ";|{|}|=|(|,|%op% %varid% [", varid) || - Token::Match(tok->previous(), ";|{|}|=|(|,|%op% %varid% .", varid)) { + } else if (Token::Match(tok->previous(), ";|{|}|=|(|,|%cop% %varid% [", varid) || + Token::Match(tok->previous(), ";|{|}|=|(|,|%cop% %varid% .", varid)) { // warning is written for "dealloc ; use_ ;". // but this use doesn't affect the leak-checking addtoken(&rettail, tok, "use_"); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 46cb5d3d6..22575b143 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -486,7 +486,7 @@ private: } // Used.. - if (Token::Match(tok.previous(), "[[(,+-*/|=] %var% ]|)|,|;|%op%")) { + if (Token::Match(tok.previous(), "[[(,+-*/|=] %var% ]|)|,|;|%op%") && !tok.next()->isAssignmentOp()) { // Taking address of array.. std::list::const_iterator it; for (it = checks.begin(); it != checks.end(); ++it) { @@ -1357,7 +1357,7 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok, // variable is seen.. if (tok->varId() == var.varId()) { if (!membervar.empty()) { - if (Token::Match(tok, "%var% . %var% ;|%op%") && tok->strAt(2) == membervar) + if (Token::Match(tok, "%var% . %var% ;|%cop%") && tok->strAt(2) == membervar) uninitStructMemberError(tok, tok->str() + "." + membervar); else return true; @@ -1521,7 +1521,7 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, bool cpp } } - if (Token::Match(vartok->previous(), "++|--|%op%")) { + if (Token::Match(vartok->previous(), "++|--|%cop%")) { if (cpp && vartok->previous()->str() == ">>") { // assume that variable is initialized return false; @@ -1581,7 +1581,7 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, bool cpp return (var && var->typeStartToken()->isStandardType()); } - if (Token::Match(vartok->next(), "++|--|%op%")) + if (vartok->next() && vartok->next()->isOp() && !vartok->next()->isAssignmentOp()) return true; if (vartok->strAt(1) == "]") @@ -1597,7 +1597,7 @@ bool CheckUninitVar::isMemberVariableAssignment(const Token *tok, const std::str return true; else if (Token::Match(tok->tokAt(-2), "[(,=] &")) return true; - else if (Token::Match(tok->previous(), "%op%") || Token::Match(tok->previous(), "[|=")) + else if ((tok->previous() && tok->previous()->isConstOp()) || Token::Match(tok->previous(), "[|=")) ; // member variable usage else return true; diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index d7580a93b..43e71ca57 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -794,7 +794,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens) // keep parentheses here: Functor()(a ... ) // keep parentheses here: ) ( var ) ; if ((Token::Match(tok->next(), "( %var% ) ;|)|,|]") || - (Token::Match(tok->next(), "( %var% ) %op%") && (tok->tokAt(2)->varId()>0 || !Token::Match(tok->tokAt(4), "[*&]")))) && + (Token::Match(tok->next(), "( %var% ) %cop%") && (tok->tokAt(2)->varId()>0 || !Token::Match(tok->tokAt(4), "[*&]")))) && !tok->isName() && tok->str() != ">" && tok->str() != "]" && @@ -853,19 +853,19 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens) tok->deleteNext(); tok->deleteThis(); ret = true; - } else if (Token::Match(tok->previous(), "[=[(,] 0 * %var% ,|]|)|;|=|%op%") || - Token::Match(tok->previous(), "[=[(,] 0 * %num% ,|]|)|;|=|%op%") || - Token::Match(tok->previous(), "[=[(,] 0 * ( ,|]|)|;|=|%op%") || - Token::Match(tok->previous(), "return|case 0 *|&& %var% ,|:|;|=|%op%") || - Token::Match(tok->previous(), "return|case 0 *|&& %num% ,|:|;|=|%op%") || - Token::Match(tok->previous(), "return|case 0 *|&& ( ,|:|;|=|%op%")) { + } else if (Token::Match(tok->previous(), "[=[(,] 0 * %var% ,|]|)|;|=|%cop%") || + Token::Match(tok->previous(), "[=[(,] 0 * %num% ,|]|)|;|%op%") || + Token::Match(tok->previous(), "[=[(,] 0 * (") || + Token::Match(tok->previous(), "return|case 0 *|&& %var% ,|:|;|=|%cop%") || + Token::Match(tok->previous(), "return|case 0 *|&& %num% ,|:|;|%op%") || + Token::Match(tok->previous(), "return|case 0 *|&& (")) { tok->deleteNext(); if (tok->next()->str() == "(") Token::eraseTokens(tok, tok->next()->link()); tok->deleteNext(); ret = true; - } else if (Token::Match(tok->previous(), "[=[(,] 0 && *|& %any% ,|]|)|;|=|%op%") || - Token::Match(tok->previous(), "return|case 0 && *|& %any% ,|:|;|=|%op%")) { + } else if (Token::Match(tok->previous(), "[=[(,] 0 && *|& %any% ,|]|)|;|=|%cop%") || + Token::Match(tok->previous(), "return|case 0 && *|& %any% ,|:|;|=|%cop%")) { tok->deleteNext(); tok->deleteNext(); if (tok->next()->str() == "(") @@ -876,15 +876,15 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens) } if (tok->str() == "1") { - if (Token::Match(tok->previous(), "[=[(,] 1 %oror% %any% ,|]|)|;|=|%op%") || - Token::Match(tok->previous(), "return|case 1 %oror% %any% ,|:|;|=|%op%")) { + if (Token::Match(tok->previous(), "[=[(,] 1 %oror% %any% ,|]|)|;|=|%cop%") || + Token::Match(tok->previous(), "return|case 1 %oror% %any% ,|:|;|=|%cop%")) { tok->deleteNext(); if (tok->next()->str() == "(") Token::eraseTokens(tok, tok->next()->link()); tok->deleteNext(); ret = true; - } else if (Token::Match(tok->previous(), "[=[(,] 1 %oror% *|& %any% ,|]|)|;|=|%op%") || - Token::Match(tok->previous(), "return|case 1 %oror% *|& %any% ,|:|;|=|%op%")) { + } else if (Token::Match(tok->previous(), "[=[(,] 1 %oror% *|& %any% ,|]|)|;|=|%cop%") || + Token::Match(tok->previous(), "return|case 1 %oror% *|& %any% ,|:|;|=|%cop%")) { tok->deleteNext(); tok->deleteNext(); if (tok->next()->str() == "(") diff --git a/lib/token.cpp b/lib/token.cpp index bb49749e5..7bbe95278 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -312,9 +312,16 @@ static int multiComparePercent(const Token *tok, const char * * haystack_p, if (haystack[1] == 'o' && // "%op%" haystack[2] == 'p' && haystack[3] == '%') { - if (tok->isConstOp()) + if (tok->isOp()) return 1; *haystack_p = haystack = haystack + 4; + } else if (haystack[1] == 'c' && // "%cop%" + haystack[2] == 'o' && + haystack[3] == 'p' && + haystack[4] == '%') { + if (tok->isConstOp()) + return 1; + *haystack_p = haystack = haystack + 5; } else if (haystack[1] == 'o' && // "%or%" haystack[2] == 'r' && haystack[3] == '%') { @@ -349,7 +356,7 @@ int Token::multiCompare(const Token *tok, const char *haystack, const char *need haystack[3] == '%' && haystack[4] == '|') { haystack = haystack + 5; - if (tok->isConstOp()) + if (tok->isOp()) return 1; } else if (haystack[2] == 'r' && // "%or%|" haystack[3] == '%' && @@ -366,6 +373,12 @@ int Token::multiCompare(const Token *tok, const char *haystack, const char *need if (needle[0] == '|' && needle[1] == '|') return 1; } + } else if (haystack[0] == '%' && haystack[1] == 'c' && haystack[2] == 'o' && // "%cop%|" + haystack[3] == 'p' && haystack[4] == '%' && + haystack[5] == '|') { + haystack = haystack + 6; + if (tok->isConstOp()) + return 1; } bool emptyStringFound = false; @@ -600,6 +613,11 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid) p += 4; multicompare(p,tok->type() == eChar,ismulticomp); } + // Const operator (%cop%) + else if (p[1] == 'p') { + p += 3; + multicompare(p,tok->isConstOp(),ismulticomp); + } // Comparison operator (%comp%) else { p += 4; @@ -627,7 +645,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid) // Op (%op%) if (p[0] == 'p') { p += 2; - multicompare(p,tok->isConstOp(),ismulticomp); + multicompare(p,tok->isOp(),ismulticomp); } // Or (%or%) else { diff --git a/lib/token.h b/lib/token.h index fed3d07f9..494f95943 100644 --- a/lib/token.h +++ b/lib/token.h @@ -136,6 +136,7 @@ public: * - "%str%" Any token starting with "-character (C-string). * - "%varid%" Match with parameter varid * - "%op%" Any token such that isConstOp() returns true. + * - "%cop%" Any token such that isConstOp() returns true. * - "%or%" A bitwise-or operator '|' * - "%oror%" A logical-or operator '||' * - "[abc]" Any of the characters 'a' or 'b' or 'c' diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b6cfcc012..22e9ae458 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2255,7 +2255,7 @@ void Tokenizer::simplifyNull() void Tokenizer::concatenateNegativeNumberAndAnyPositive() { for (Token *tok = list.front(); tok; tok = tok->next()) { - if (!Token::Match(tok, "?|:|,|(|[|{|=|return|case|sizeof|%op% +|-")) + if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->type() == Token::eIncDecOp) continue; if (tok->next()->str() == "+") tok->deleteNext(); @@ -4955,7 +4955,7 @@ bool Tokenizer::simplifyFunctionReturn() else if (Token::Match(tok, "%var% ( ) { return %bool%|%char%|%num%|%str% ; }")) { const Token* const any = tok->tokAt(5); - const std::string pattern("(|[|=|%op% " + tok->str() + " ( ) ;|]|)|%op%"); + const std::string pattern("(|[|=|%cop% " + tok->str() + " ( ) ;|]|)|%cop%"); for (Token *tok2 = list.front(); tok2; tok2 = tok2->next()) { if (Token::Match(tok2, pattern.c_str())) { tok2 = tok2->next(); @@ -5944,7 +5944,7 @@ bool Tokenizer::simplifyKnownVariables() //check if there's not a reference usage inside the code bool withreference = false; for (const Token *tok2 = valuetok->tokAt(2); tok2; tok2 = tok2->next()) { - if (Token::Match(tok2,"(|[|,|{|=|return|%op% & %varid%", vartok->varId())) { + if (Token::Match(tok2,"(|[|,|{|return|%op% & %varid%", vartok->varId())) { withreference = true; break; } @@ -6444,7 +6444,7 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign } // array usage - if (value[0] != '\"' && Token::Match(tok3, ("[(,] " + structname + " %varid% [|%op%").c_str(), varid)) { + if (value[0] != '\"' && Token::Match(tok3, ("[(,] " + structname + " %varid% [|%cop%").c_str(), varid)) { if (!structname.empty()) { tok3->deleteNext(2); } @@ -6468,7 +6468,7 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) || (Token::Match(tok3, ("[=+-*/%^|[] " + structname + " %varid% [=?+-*/%^|;])]").c_str(), varid) && !Token::Match(tok3, ("= " + structname + " %var% =").c_str())) || Token::Match(tok3, ("[(=+-*/%^|[] " + structname + " %varid% <<|>>").c_str(), varid) || - Token::Match(tok3, ("<<|>> " + structname + " %varid% %op%|;|]|)").c_str(), varid) || + Token::Match(tok3, ("<<|>> " + structname + " %varid% %cop%|;|]|)").c_str(), varid) || Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid% !!=").c_str(), varid)) { if (value[0] == '\"') break; @@ -6716,7 +6716,7 @@ bool Tokenizer::simplifyRedundantParentheses() } // Simplify "!!operator !!(%var%|)) ( %num%|%bool% ) %op%|;|,|)" - if (Token::Match(tok, "( %bool%|%num% ) %op%|;|,|)") && + if (Token::Match(tok, "( %bool%|%num% ) %cop%|;|,|)") && !Token::simpleMatch(tok->tokAt(-2), "operator") && tok->previous() && !tok->previous()->isName() && @@ -9244,7 +9244,7 @@ void Tokenizer::simplifyOperatorName() } done = false; } - if (Token::Match(par, "=|.|++|--|%op%")) { + if (Token::Match(par, ".|%op%")) { op += par->str(); par = par->next(); done = false; diff --git a/test/testtoken.cpp b/test/testtoken.cpp index f31512cdf..8651de600 100644 --- a/test/testtoken.cpp +++ b/test/testtoken.cpp @@ -65,6 +65,7 @@ private: TEST_CASE(matchBoolean); TEST_CASE(matchOr); TEST_CASE(matchOp); + TEST_CASE(matchConstOp); TEST_CASE(isArithmeticalOp); TEST_CASE(isOp); @@ -453,7 +454,7 @@ private: givenACodeSampleToTokenize bitwiseOrAssignment("|="); ASSERT_EQUALS(false, Token::Match(bitwiseOrAssignment.tokens(), "%or%")); - ASSERT_EQUALS(false, Token::Match(bitwiseOrAssignment.tokens(), "%op%")); + ASSERT_EQUALS(true, Token::Match(bitwiseOrAssignment.tokens(), "%op%")); ASSERT_EQUALS(false, Token::Match(bitwiseOrAssignment.tokens(), "%oror%")); givenACodeSampleToTokenize logicalOr("||", true); @@ -523,6 +524,7 @@ private: append_vector(test_ops, bitOps); append_vector(test_ops, comparisonOps); append_vector(test_ops, logicalOps); + append_vector(test_ops, assignmentOps); std::vector::const_iterator test_op, test_ops_end = test_ops.end(); for (test_op = test_ops.begin(); test_op != test_ops_end; ++test_op) { @@ -532,7 +534,6 @@ private: // Negative test against other operators std::vector other_ops; append_vector(other_ops, extendedOps); - append_vector(other_ops, assignmentOps); std::vector::const_iterator other_op, other_ops_end = other_ops.end(); for (other_op = other_ops.begin(); other_op != other_ops_end; ++other_op) { @@ -540,6 +541,30 @@ private: } } + void matchConstOp() { + std::vector test_ops; + append_vector(test_ops, arithmeticalOps); + append_vector(test_ops, bitOps); + append_vector(test_ops, comparisonOps); + append_vector(test_ops, logicalOps); + + std::vector::const_iterator test_op, test_ops_end = test_ops.end(); + for (test_op = test_ops.begin(); test_op != test_ops_end; ++test_op) { + ASSERT_EQUALS(true, Match(*test_op, "%cop%")); + } + + // Negative test against other operators + std::vector other_ops; + append_vector(other_ops, extendedOps); + append_vector(other_ops, assignmentOps); + + std::vector::const_iterator other_op, other_ops_end = other_ops.end(); + for (other_op = other_ops.begin(); other_op != other_ops_end; ++other_op) { + ASSERT_EQUALS_MSG(false, Match(*other_op, "%cop%"), "Failing other operator: " + *other_op); + } + } + + void isArithmeticalOp() { std::vector::const_iterator test_op, test_ops_end = arithmeticalOps.end(); for (test_op = arithmeticalOps.begin(); test_op != test_ops_end; ++test_op) {