diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 861088d31..23b06aaed 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -83,6 +83,15 @@ std::string astCanonicalType(const Token *expr) return ""; } +static bool match(const Token *tok, const std::string &rhs) +{ + if (tok->str() == rhs) + return true; + if (tok->isName() && !tok->varId() && tok->values.size() == 1U && tok->values.front().isKnown() && MathLib::toString(tok->values.front().intvalue) == rhs) + return true; + return false; +} + const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok) { if (!tok) @@ -90,7 +99,7 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const Token *ret = nullptr; if (tok->isComparisonOp()) { - if (tok->astOperand1() && tok->astOperand1()->str() == rhs) { + if (tok->astOperand1() && match(tok->astOperand1(), rhs)) { // Invert comparator std::string s = tok->str(); if (s[0] == '>') @@ -100,7 +109,7 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp, if (s == comp) { ret = tok->astOperand2(); } - } else if (tok->str() == comp && tok->astOperand2() && tok->astOperand2()->str() == rhs) { + } else if (tok->str() == comp && tok->astOperand2() && match(tok->astOperand2(), rhs)) { ret = tok->astOperand1(); } } else if (comp == "!=" && rhs == std::string("0")) { diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index dfb207e18..a6b007725 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -983,6 +983,13 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const variables.write(varid1, tok); } else if (varid1 && Token::Match(tok, "%varid% .", varid1)) { variables.use(varid1, tok); + } else if (var && + var->_type == Variables::pointer && + Token::Match(tok, "%name% ;") && + tok->varId() == 0 && + tok->hasKnownIntValue() && + tok->values.front().intvalue == 0) { + variables.use(varid1, tok); } else { variables.write(varid1, tok); } diff --git a/lib/token.h b/lib/token.h index ae950b634..7ab5456b9 100644 --- a/lib/token.h +++ b/lib/token.h @@ -748,6 +748,10 @@ public: /** Values of token */ std::list values; + bool hasKnownIntValue() const { + return values.size() == 1U && values.front().isKnown() && values.front().tokvalue == nullptr; + } + const ValueFlow::Value * getValue(const MathLib::bigint val) const { std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 5cb868a48..248fe2d94 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1889,26 +1889,6 @@ void Tokenizer::combineStringAndCharLiterals() } } -void Tokenizer::simplifyNull() -{ - for (Token *tok = list.front(); tok; tok = tok->next()) { - if (tok->str() == "NULL" && (!Token::Match(tok->previous(), "[(,] NULL [,)]") || tok->strAt(-2) == "=")) - tok->str("0"); - else if (tok->str() == "__null") { - tok->originalName(tok->str()); - tok->str("0"); - } - } - - // nullptr.. - if (isCPP() && _settings->standards.cpp == Standards::CPP11) { - for (Token *tok = list.front(); tok; tok = tok->next()) { - if (tok->str() == "nullptr") - tok->str("0"); - } - } -} - void Tokenizer::concatenateNegativeNumberAndAnyPositive() { for (Token *tok = list.front(); tok; tok = tok->next()) { @@ -3362,9 +3342,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // Simplify the C alternative tokens (and, or, etc.) simplifyCAlternativeTokens(); - // replace 'NULL' and similar '0'-defined macros with '0' - simplifyNull(); - // replace 'sin(0)' to '0' and other similar math expressions simplifyMathExpressions(); diff --git a/lib/tokenize.h b/lib/tokenize.h index bf805e759..7c259d251 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -468,8 +468,6 @@ public: void combineStringAndCharLiterals(); - void simplifyNull(); - void concatenateNegativeNumberAndAnyPositive(); void simplifyExternC(); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 4b8c7317d..1576bb448 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -604,7 +604,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) // Handle various constants.. -static Token * valueFlowSetConstantValue(const Token *tok, const Settings *settings) +static Token * valueFlowSetConstantValue(const Token *tok, const Settings *settings, bool cpp) { if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) { ValueFlow::Value value(MathLib::toLongNumber(tok->str())); @@ -614,6 +614,10 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti ValueFlow::Value value(tok->enumerator()->value); value.setKnown(); setTokenValue(const_cast(tok), value); + } else if (tok->str() == "NULL" || (cpp && tok->str() == "nullptr")) { + ValueFlow::Value value(0); + value.setKnown(); + setTokenValue(const_cast(tok), value); } else if (Token::simpleMatch(tok, "sizeof (") && tok->tokAt(2)) { const Token *tok2 = tok->tokAt(2); if (tok2->enumerator() && tok2->enumerator()->scope) { @@ -655,7 +659,7 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti static void valueFlowNumber(TokenList *tokenlist) { for (Token *tok = tokenlist->front(); tok;) { - tok = valueFlowSetConstantValue(tok, tokenlist->getSettings()); + tok = valueFlowSetConstantValue(tok, tokenlist->getSettings(), tokenlist->isCPP()); } if (tokenlist->isCPP()) { @@ -983,12 +987,12 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, SymbolDatabase *symbo MathLib::bigint num = 0; const Token *vartok = nullptr; if (tok->isComparisonOp() && tok->astOperand1() && tok->astOperand2()) { - if (tok->astOperand1()->isName() && tok->astOperand2()->isNumber()) { + if (tok->astOperand1()->isName() && tok->astOperand2()->hasKnownIntValue()) { vartok = tok->astOperand1(); - num = MathLib::toLongNumber(tok->astOperand2()->str()); - } else if (tok->astOperand1()->isNumber() && tok->astOperand2()->isName()) { + num = tok->astOperand2()->values.front().intvalue; + } else if (tok->astOperand1()->hasKnownIntValue() && tok->astOperand2()->isName()) { vartok = tok->astOperand2(); - num = MathLib::toLongNumber(tok->astOperand1()->str()); + num = tok->astOperand1()->values.front().intvalue; } else { continue; } @@ -1708,7 +1712,7 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol if (Token::Match(tok, "==|!=|>=|<=")) { if (!tok->astOperand1() || !tok->astOperand2()) continue; - if (tok->astOperand1()->isNumber()) { + if (tok->astOperand1()->hasKnownIntValue()) { numtok = tok->astOperand1(); vartok = tok->astOperand2(); } else { @@ -1717,7 +1721,7 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol } if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2()) vartok = vartok->astOperand1(); - if (!vartok->isName() || !numtok->isNumber() || !MathLib::isInt(numtok->str())) + if (!vartok->isName() || !numtok->hasKnownIntValue()) continue; } else if (tok->str() == "!") { vartok = tok->astOperand1(); @@ -1742,7 +1746,7 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol if (!var || !(var->isLocal() || var->isArgument())) continue; std::list values; - values.push_back(ValueFlow::Value(tok, numtok ? MathLib::toLongNumber(numtok->str()) : 0LL)); + values.push_back(ValueFlow::Value(tok, numtok ? numtok->values.front().intvalue : 0LL)); if (Token::Match(tok->astParent(), "%oror%|&&")) { Token *parent = const_cast(tok->astParent()); @@ -2549,7 +2553,7 @@ const ValueFlow::Value *ValueFlow::valueFlowConstantFoldAST(const Token *expr, c if (expr && expr->values.empty()) { valueFlowConstantFoldAST(expr->astOperand1(), settings); valueFlowConstantFoldAST(expr->astOperand2(), settings); - valueFlowSetConstantValue(expr, settings); + valueFlowSetConstantValue(expr, settings, true /* TODO: this is a guess */); } return expr && expr->values.size() == 1U && expr->values.front().isKnown() ? &expr->values.front() : nullptr; } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 6acafbcec..8a0475bd0 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -1669,7 +1669,7 @@ private: " return;\n" " }\n" "}"); - ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:3]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:3]: (warning) Either the condition 'p==NULL' is redundant or there is possible null pointer dereference: p.\n", errout.str()); // check, and use check("void f(struct X *p, int x) {\n" @@ -1689,7 +1689,7 @@ private: ASSERT_EQUALS("", errout.str()); check(code, true); // inconclusive - ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning, inconclusive) Either the condition 'fred==0' is redundant or there is possible null pointer dereference: fred.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning, inconclusive) Either the condition 'fred==NULL' is redundant or there is possible null pointer dereference: fred.\n", errout.str()); } check("void f(char *s) {\n" // #3358 diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 890a03ae4..dfc00eaea 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -1592,7 +1592,7 @@ private: "{ " "FILE * f ; " "f = fopen ( \"foo\" , \"r\" ) ; " - "if ( f == 0 ) " + "if ( f == NULL ) " "{ " "return -1 ; " "} " @@ -1669,7 +1669,7 @@ private: ASSERT_EQUALS("char * s ; do { s = new char [ 10 ] ; } while ( ! s ) ;", tok("char *s; do { } while (0 == (s=new char[10]));")); // #4911 - ASSERT_EQUALS("; do { current = f ( ) ; } while ( ( current ) != 0 ) ;", simplifyIfAndWhileAssign(";do { } while((current=f()) != NULL);")); + ASSERT_EQUALS("; do { current = f ( ) ; } while ( ( current ) != NULL ) ;", simplifyIfAndWhileAssign(";do { } while((current=f()) != NULL);")); } void not1() { diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index bcb6ca631..cbc7115e9 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -1707,7 +1707,7 @@ private: { const char code[] = "typedef int RexxFunctionHandler();\n" "RexxFunctionHandler *(efuncs[]) = { NULL, NULL };"; - const char expected[] = "int ( * ( efuncs [ ] ) ) ( ) = { 0 , 0 } ;"; + const char expected[] = "int ( * ( efuncs [ ] ) ) ( ) = { NULL , NULL } ;"; ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS("", errout.str()); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 3da6e1f5b..faf7e3047 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -241,7 +241,6 @@ private: TEST_CASE(simplify_constants4); TEST_CASE(simplify_constants5); TEST_CASE(simplify_constants6); // Ticket #5625: Ternary operator as template parameter - TEST_CASE(simplifyNull); TEST_CASE(simplifyMulAndParens); // Ticket #2784 + #3184 TEST_CASE(simplifyStructDecl); @@ -2675,7 +2674,7 @@ private: " nr = (last = list->prev)->nr;\n" // <- don't replace "last" with 0 "}\n"; const char expected[] = "void f ( struct ABC * list ) {\n" - "struct ABC * last ; last = 0 ;\n" + "struct ABC * last ; last = NULL ;\n" "nr = ( last = list . prev ) . nr ;\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, true)); @@ -3394,24 +3393,6 @@ private: } } - void simplifyNull() { - { - const char code[] = - "int * p = NULL;\n" - "int * q = __null;\n"; - const char expected[] = - "int * p ; p = 0 ;\nint * q ; q = 0 ;"; - ASSERT_EQUALS(expected, tokenizeAndStringify(code,true)); - } - - ASSERT_EQUALS("( a == nullptr )", tokenizeAndStringify("(a==nullptr)", false, false, Settings::Native, "test.c")); - ASSERT_EQUALS("( a == 0 )", tokenizeAndStringify("(a==nullptr)", false, false, Settings::Native, "test.cpp")); - - ASSERT_EQUALS("if ( p == 0 )", tokenizeAndStringify("if (p==NULL)")); - ASSERT_EQUALS("f ( NULL ) ;", tokenizeAndStringify("f(NULL);")); - ASSERT_EQUALS("char * i ; i = 0 ;", tokenizeAndStringify("char* i = (NULL);")); - } - void simplifyMulAndParens() { // (error) Resource leak const char code[] = "void f() {" @@ -3482,19 +3463,19 @@ private: // ticket #346 const char code1[] = "void *p = NULL;"; - const char res1[] = "void * p ; p = 0 ;"; + const char res1[] = "void * p ; p = NULL ;"; ASSERT_EQUALS(res1, tokenizeAndStringify(code1)); const char code2[] = "const void *p = NULL;"; - const char res2[] = "const void * p ; p = 0 ;"; + const char res2[] = "const void * p ; p = NULL ;"; ASSERT_EQUALS(res2, tokenizeAndStringify(code2)); const char code3[] = "void * const p = NULL;"; - const char res3[] = "void * const p ; p = 0 ;"; + const char res3[] = "void * const p ; p = NULL ;"; ASSERT_EQUALS(res3, tokenizeAndStringify(code3)); const char code4[] = "const void * const p = NULL;"; - const char res4[] = "const void * const p ; p = 0 ;"; + const char res4[] = "const void * const p ; p = NULL ;"; ASSERT_EQUALS(res4, tokenizeAndStringify(code4)); } @@ -3562,7 +3543,7 @@ private: // ticket #3927 const char code3[] = "union xy *p = NULL;"; - ASSERT_EQUALS("union xy * p ; p = 0 ;", tokenizeAndStringify(code3)); + ASSERT_EQUALS("union xy * p ; p = NULL ;", tokenizeAndStringify(code3)); } void vardecl_par() {