diff --git a/gui/test/data/benchmark/simple.cpp b/gui/test/data/benchmark/simple.cpp deleted file mode 100644 index 4c90985e7..000000000 --- a/gui/test/data/benchmark/simple.cpp +++ /dev/null @@ -1,3511 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2021 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -//--------------------------------------------------------------------------- -// Remove includes from the benchmark run -// Included files aren't found anyway -//#include "checkother.h" -//#include "mathlib.h" -//#include "symboldatabase.h" - -//#include // std::isupper -//#include // fabs() -//#include -//--------------------------------------------------------------------------- - -// Register this check class (by creating a static instance of it) -namespace { - CheckOther instance; -} - -//--------------------------------------------------------------------------- - -void CheckOther::checkIncrementBoolean() -{ - if (!_settings->isEnabled("style")) - return; - - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "%var% ++")) { - if (tok->varId()) { - const Token *declTok = Token::findmatch(_tokenizer->tokens(), "bool %varid%", tok->varId()); - if (declTok) - incrementBooleanError(tok); - } - } - } -} - -void CheckOther::incrementBooleanError(const Token *tok) -{ - reportError( - tok, - Severity::style, - "incrementboolean", - "The use of a variable of type bool with the ++ postfix operator is always true and deprecated by the C++ Standard.\n" - "The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true\n" - ); -} - -//--------------------------------------------------------------------------- - - -void CheckOther::clarifyCalculation() -{ - if (!_settings->isEnabled("style")) - return; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (tok->strAt(1) == "?") { - // condition - const Token *cond = tok; - if (cond->isName() || cond->isNumber()) - cond = cond->previous(); - else if (cond->str() == ")") - cond = cond->link()->previous(); - else - continue; - - // calculation - if (!cond->isArithmeticalOp()) - continue; - - const std::string &op = cond->str(); - cond = cond->previous(); - - // skip previous multiplications.. - while (cond && cond->strAt(-1) == "*" && (cond->isName() || cond->isNumber())) - cond = cond->tokAt(-2); - - if (!cond) - continue; - - // first multiplication operand - if (cond->str() == ")") { - clarifyCalculationError(cond, op); - } else if (cond->isName() || cond->isNumber()) { - if (Token::Match(cond->previous(),("return|=|+|-|,|(|"+op).c_str())) - clarifyCalculationError(cond, op); - } - } - } -} - -void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op) -{ - // suspicious calculation - const std::string calc("'a" + op + "b?c:d'"); - - // recommended calculation #1 - const std::string s1("'(a" + op + "b)?c:d'"); - - // recommended calculation #2 - const std::string s2("'a" + op + "(b?c:d)'"); - - reportError(tok, - Severity::style, - "clarifyCalculation", - "Clarify calculation precedence for " + op + " and ?\n" - "Suspicious calculation. Please use parentheses to clarify the code. " - "The code " + calc + " should be written as either " + s1 + " or " + s2 + "."); -} - - -// Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))' -void CheckOther::clarifyCondition() -{ - if (!_settings->isEnabled("style")) - return; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "( %var% =")) { - for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) { - if (tok2->str() == "(" || tok2->str() == "[") - tok2 = tok2->link(); - else if (Token::Match(tok2, "&&|%oror%|?|)")) - break; - else if (Token::Match(tok2, "<|<=|==|!=|>|>= %num% )")) { - clarifyConditionError(tok); - break; - } - } - } - } -} - -void CheckOther::clarifyConditionError(const Token *tok) -{ - reportError(tok, - Severity::style, - "clarifyCondition", - "Suspicious condition (assignment+comparison), it can be clarified with parentheses"); -} - - - -void CheckOther::warningOldStylePointerCast() -{ - if (!_settings->isEnabled("style") || - (_tokenizer->tokens() && _tokenizer->fileLine(_tokenizer->tokens()).find(".cpp") == std::string::npos)) - return; - - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - // Old style pointer casting.. - if (!Token::Match(tok, "( const| %type% * ) %var%") && - !Token::Match(tok, "( const| %type% * ) (| new")) - continue; - - int addToIndex = 0; - if (tok->tokAt(1)->str() == "const") - addToIndex = 1; - - if (tok->tokAt(4 + addToIndex)->str() == "const") - continue; - - // Is "type" a class? - const std::string pattern("class " + tok->tokAt(1 + addToIndex)->str()); - if (!Token::findmatch(_tokenizer->tokens(), pattern.c_str())) - continue; - - cstyleCastError(tok); - } -} - -//--------------------------------------------------------------------------- -// fflush(stdin) <- fflush only applies to output streams in ANSI C -//--------------------------------------------------------------------------- -void CheckOther::checkFflushOnInputStream() -{ - const Token *tok = _tokenizer->tokens(); - while (tok && ((tok = Token::findsimplematch(tok, "fflush ( stdin )")) != NULL)) { - fflushOnInputStreamError(tok, tok->strAt(2)); - tok = tok->tokAt(4); - } -} - -void CheckOther::checkSizeofForNumericParameter() -{ - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "sizeof ( %num% )") - || Token::Match(tok, "sizeof ( - %num% )") - || Token::Match(tok, "sizeof %num%") - || Token::Match(tok, "sizeof - %num%") - ) { - sizeofForNumericParameterError(tok); - } - } -} - -void CheckOther::checkSizeofForArrayParameter() -{ - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "sizeof ( %var% )") || Token::Match(tok, "sizeof %var%")) { - int tokIdx = 1; - if (tok->tokAt(tokIdx)->str() == "(") { - ++tokIdx; - } - if (tok->tokAt(tokIdx)->varId() > 0) { - const Token *declTok = Token::findmatch(_tokenizer->tokens(), "%varid%", tok->tokAt(tokIdx)->varId()); - if (declTok) { - if (Token::simpleMatch(declTok->next(), "[")) { - declTok = declTok->next()->link(); - // multidimensional array - while (Token::simpleMatch(declTok->next(), "[")) { - declTok = declTok->next()->link(); - } - if (!(Token::Match(declTok->next(), "= %str%")) && !(Token::simpleMatch(declTok->next(), "= {")) && !(Token::simpleMatch(declTok->next(), ";"))) { - if (Token::simpleMatch(declTok->next(), ",")) { - declTok = declTok->next(); - while (!Token::simpleMatch(declTok, ";")) { - if (Token::simpleMatch(declTok, ")")) { - sizeofForArrayParameterError(tok); - break; - } - if (Token::Match(declTok, "(|[|{")) { - declTok = declTok->link(); - } - declTok = declTok->next(); - } - } - } - if (Token::simpleMatch(declTok->next(), ")")) { - sizeofForArrayParameterError(tok); - } - } - } - } - } - } -} - - - -//--------------------------------------------------------------------------- -// switch (x) -// { -// case 2: -// y = a; // <- this assignment is redundant -// case 3: -// y = b; // <- case 2 falls through and sets y twice -// } -//--------------------------------------------------------------------------- -void CheckOther::checkRedundantAssignmentInSwitch() -{ - const char switchPattern[] = "switch ( %any% ) { case"; - const char breakPattern[] = "break|continue|return|exit|goto|throw"; - const char functionPattern[] = "%var% ("; - - // Find the beginning of a switch. E.g.: - // switch (var) { ... - const Token *tok = Token::findmatch(_tokenizer->tokens(), switchPattern); - while (tok) { - - // Check the contents of the switch statement - std::map varsAssigned; - int indentLevel = 0; - for (const Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next()) { - if (tok2->str() == "{") { - // Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.: - // case 3: b = 1; - // case 4: if (a) { b = 2; } // Doesn't make the b=1 redundant because it's conditional - if (Token::Match(tok2->previous(), ")|else {") && tok2->link()) { - const Token* endOfConditional = tok2->link(); - for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next()) { - if (tok3->varId() != 0) - varsAssigned.erase(tok3->varId()); - else if (Token::Match(tok3, functionPattern) || Token::Match(tok3, breakPattern)) - varsAssigned.clear(); - } - tok2 = endOfConditional; - } else - ++indentLevel; - } else if (tok2->str() == "}") { - --indentLevel; - - // End of the switch block - if (indentLevel < 0) - break; - } - - // Variable assignment. Report an error if it's assigned to twice before a break. E.g.: - // case 3: b = 1; // <== redundant - // case 4: b = 2; - if (Token::Match(tok2->previous(), ";|{|}|: %var% = %any% ;") && tok2->varId() != 0) { - std::map::iterator i = varsAssigned.find(tok2->varId()); - if (i == varsAssigned.end()) - varsAssigned[tok2->varId()] = tok2; - else - redundantAssignmentInSwitchError(i->second, i->second->str()); - } - // Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.: - // case 3: b = 1; - // case 4: b++; - else if (tok2->varId() != 0) - varsAssigned.erase(tok2->varId()); - - // Reset our record of assignments if there is a break or function call. E.g.: - // case 3: b = 1; break; - if (Token::Match(tok2, functionPattern) || Token::Match(tok2, breakPattern)) - varsAssigned.clear(); - - } - - tok = Token::findmatch(tok->next(), switchPattern); - } -} - - -void CheckOther::checkSwitchCaseFallThrough() -{ - if (!(_settings->isEnabled("style") && _settings->experimental)) - return; - - const char switchPattern[] = "switch ("; - const char breakPattern[] = "break|continue|return|exit|goto|throw"; - - // Find the beginning of a switch. E.g.: - // switch (var) { ... - const Token *tok = Token::findmatch(_tokenizer->tokens(), switchPattern); - while (tok) { - - // Check the contents of the switch statement - std::stack> ifnest; - std::stack loopnest; - std::stack scopenest; - bool justbreak = true; - bool firstcase = true; - for (const Token *tok2 = tok->tokAt(1)->link()->tokAt(2); tok2; tok2 = tok2->next()) { - if (Token::simpleMatch(tok2, "if (")) { - tok2 = tok2->tokAt(1)->link()->next(); - if (tok2->link() == NULL) { - std::ostringstream errmsg; - errmsg << "unmatched if in switch: " << tok2->linenr(); - reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); - break; - } - ifnest.emplace(tok2->link(), false); - justbreak = false; - } else if (Token::simpleMatch(tok2, "while (")) { - tok2 = tok2->tokAt(1)->link()->next(); - // skip over "do { } while ( ) ;" case - if (tok2->str() == "{") { - if (tok2->link() == NULL) { - std::ostringstream errmsg; - errmsg << "unmatched while in switch: " << tok2->linenr(); - reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); - break; - } - loopnest.push(tok2->link()); - } - justbreak = false; - } else if (Token::simpleMatch(tok2, "do {")) { - tok2 = tok2->tokAt(1); - if (tok2->link() == NULL) { - std::ostringstream errmsg; - errmsg << "unmatched do in switch: " << tok2->linenr(); - reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); - break; - } - loopnest.push(tok2->link()); - justbreak = false; - } else if (Token::simpleMatch(tok2, "for (")) { - tok2 = tok2->tokAt(1)->link()->next(); - if (tok2->link() == NULL) { - std::ostringstream errmsg; - errmsg << "unmatched for in switch: " << tok2->linenr(); - reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); - break; - } - loopnest.push(tok2->link()); - justbreak = false; - } else if (Token::Match(tok2, switchPattern)) { - // skip over nested switch, we'll come to that soon - tok2 = tok2->tokAt(1)->link()->next()->link(); - } else if (Token::Match(tok2, breakPattern)) { - if (loopnest.empty()) { - justbreak = true; - } - tok2 = Token::findsimplematch(tok2, ";"); - } else if (Token::Match(tok2, "case|default")) { - if (!justbreak && !firstcase) { - switchCaseFallThrough(tok2); - } - tok2 = Token::findsimplematch(tok2, ":"); - justbreak = true; - firstcase = false; - } else if (tok2->str() == "{") { - scopenest.push(tok2->link()); - } else if (tok2->str() == "}") { - if (!ifnest.empty() && tok2 == ifnest.top().first) { - if (tok2->next()->str() == "else") { - tok2 = tok2->tokAt(2); - ifnest.pop(); - if (tok2->link() == NULL) { - std::ostringstream errmsg; - errmsg << "unmatched if in switch: " << tok2->linenr(); - reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); - break; - } - ifnest.emplace(tok2->link(), justbreak); - justbreak = false; - } else { - justbreak &= ifnest.top().second; - ifnest.pop(); - } - } else if (!loopnest.empty() && tok2 == loopnest.top()) { - loopnest.pop(); - } else if (!scopenest.empty() && tok2 == scopenest.top()) { - scopenest.pop(); - } else { - if (!ifnest.empty() || !loopnest.empty() || !scopenest.empty()) { - std::ostringstream errmsg; - errmsg << "unexpected end of switch: "; - errmsg << "ifnest=" << ifnest.size(); - if (!ifnest.empty()) - errmsg << "," << ifnest.top().first->linenr(); - errmsg << ", loopnest=" << loopnest.size(); - if (!loopnest.empty()) - errmsg << "," << loopnest.top()->linenr(); - errmsg << ", scopenest=" << scopenest.size(); - if (!scopenest.empty()) - errmsg << "," << scopenest.top()->linenr(); - reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str()); - } - // end of switch block - break; - } - } else if (tok2->str() != ";") { - justbreak = false; - } - - } - - tok = Token::findmatch(tok->next(), switchPattern); - } -} - - -//--------------------------------------------------------------------------- -// int x = 1; -// x = x; // <- redundant assignment to self -// -// int y = y; // <- redundant initialization to self -//--------------------------------------------------------------------------- -void CheckOther::checkSelfAssignment() -{ - if (!_settings->isEnabled("style")) - return; - - // POD variables.. - std::set pod; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (tok->isStandardType() && Token::Match(tok->tokAt(2), "[,);]") && tok->next()->varId()) - pod.insert(tok->next()->varId()); - } - - const char selfAssignmentPattern[] = "%var% = %var% ;|=|)"; - const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern); - while (tok) { - if (Token::Match(tok->previous(), "[;{}]") && - tok->varId() && tok->varId() == tok->tokAt(2)->varId() && - pod.find(tok->varId()) != pod.end()) { - selfAssignmentError(tok, tok->str()); - } - - tok = Token::findmatch(tok->next(), selfAssignmentPattern); - } -} - -//--------------------------------------------------------------------------- -// int a = 1; -// assert(a = 2); // <- assert should not have a side-effect -//--------------------------------------------------------------------------- -void CheckOther::checkAssignmentInAssert() -{ - if (!_settings->isEnabled("style")) - return; - - const char assertPattern[] = "assert ( %any%"; - const Token *tok = Token::findmatch(_tokenizer->tokens(), assertPattern); - const Token *endTok = tok ? tok->next()->link() : NULL; - - while (tok && endTok) { - const Token* varTok = Token::findmatch(tok->tokAt(2), "%var% --|++|+=|-=|*=|/=|&=|^=|=", endTok); - if (varTok) { - assignmentInAssertError(tok, varTok->str()); - } else if (NULL != (varTok = Token::findmatch(tok->tokAt(2), "--|++ %var%", endTok))) { - assignmentInAssertError(tok, varTok->strAt(1)); - } - - tok = Token::findmatch(endTok->next(), assertPattern); - endTok = tok ? tok->next()->link() : NULL; - } -} - -//--------------------------------------------------------------------------- -// if ((x != 1) || (x != 3)) // <- always true -// if ((x == 1) && (x == 3)) // <- always false -// if ((x < 1) && (x > 3)) // <- always false -// if ((x > 3) || (x < 10)) // <- always true -//--------------------------------------------------------------------------- -void CheckOther::checkIncorrectLogicOperator() -{ - if (!_settings->isEnabled("style")) - return; - - const char conditionPattern[] = "if|while ("; - const Token *tok = Token::findmatch(_tokenizer->tokens(), conditionPattern); - const Token *endTok = tok ? tok->next()->link() : NULL; - - while (tok && endTok) { - // Find a pair of OR'd terms, with or without parentheses - // e.g. if (x != 3 || x != 4) - const Token *logicTok = NULL, *term1Tok = NULL, *term2Tok = NULL; - const Token *op1Tok = NULL, *op2Tok = NULL, *op3Tok = NULL, *nextTok = NULL; - if (NULL != (logicTok = Token::findmatch(tok, "( %any% !=|==|<|>|>=|<= %any% ) &&|%oror% ( %any% !=|==|<|>|>=|<= %any% ) %any%", endTok))) { - term1Tok = logicTok->next(); - term2Tok = logicTok->tokAt(7); - op1Tok = logicTok->tokAt(2); - op2Tok = logicTok->tokAt(5); - op3Tok = logicTok->tokAt(8); - nextTok = logicTok->tokAt(11); - } else if (NULL != (logicTok = Token::findmatch(tok, "%any% !=|==|<|>|>=|<= %any% &&|%oror% %any% !=|==|<|>|>=|<= %any% %any%", endTok))) { - term1Tok = logicTok; - term2Tok = logicTok->tokAt(4); - op1Tok = logicTok->tokAt(1); - op2Tok = logicTok->tokAt(3); - op3Tok = logicTok->tokAt(5); - nextTok = logicTok->tokAt(7); - } - - if (logicTok) { - // Find the common variable and the two different-valued constants - unsigned int variableTested = 0; - std::string firstConstant, secondConstant; - bool varFirst1, varFirst2; - unsigned int varId; - if (Token::Match(term1Tok, "%var% %any% %num%")) { - varId = term1Tok->varId(); - if (!varId) { - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - continue; - } - varFirst1 = true; - firstConstant = term1Tok->tokAt(2)->str(); - } else if (Token::Match(term1Tok, "%num% %any% %var%")) { - varId = term1Tok->tokAt(2)->varId(); - if (!varId) { - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - continue; - } - varFirst1 = false; - firstConstant = term1Tok->str(); - } else { - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - continue; - } - - if (Token::Match(term2Tok, "%var% %any% %num%")) { - const unsigned int varId2 = term2Tok->varId(); - if (!varId2 || varId != varId2) { - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - continue; - } - varFirst2 = true; - secondConstant = term2Tok->tokAt(2)->str(); - variableTested = varId; - } else if (Token::Match(term2Tok, "%num% %any% %var%")) { - const unsigned int varId2 = term1Tok->tokAt(2)->varId(); - if (!varId2 || varId != varId2) { - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - continue; - } - varFirst2 = false; - secondConstant = term2Tok->str(); - variableTested = varId; - } else { - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - continue; - } - - if (variableTested == 0 || firstConstant.empty() || secondConstant.empty()) { - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - continue; - } - - enum Position { First, Second, NA }; - enum Relation { Equal, NotEqual, Less, LessEqual, More, MoreEqual }; - struct Condition { - const char *before; - Position position1; - const char *op1TokStr; - const char *op2TokStr; - Position position2; - const char *op3TokStr; - const char *after; - Relation relation; - bool state; - } conditions[] = { - { "!!&&", NA, "!=", "||", NA, "!=", "!!&&", NotEqual, true }, // (x != 1) || (x != 3) <- always true - { "(", NA, "==", "&&", NA, "==", ")", NotEqual, false }, // (x == 1) && (x == 3) <- always false - { "(", First, "<", "&&", First, ">", ")", LessEqual, false }, // (x < 1) && (x > 3) <- always false - { "(", First, ">", "&&", First, "<", ")", MoreEqual, false }, // (x > 3) && (x < 1) <- always false - { "(", Second, ">", "&&", First, ">", ")", LessEqual, false }, // (1 > x) && (x > 3) <- always false - { "(", First, ">", "&&", Second, ">", ")", MoreEqual, false }, // (x > 3) && (1 > x) <- always false - { "(", First, "<", "&&", Second, "<", ")", LessEqual, false }, // (x < 1) && (3 < x) <- always false - { "(", Second, "<", "&&", First, "<", ")", MoreEqual, false }, // (3 < x) && (x < 1) <- always false - { "(", Second, ">", "&&", Second, "<", ")", LessEqual, false }, // (1 > x) && (3 < x) <- always false - { "(", Second, "<", "&&", Second, ">", ")", MoreEqual, false }, // (3 < x) && (1 > x) <- always false - { "(", First, ">|>=", "||", First, "<|<=", ")", Less, true }, // (x > 3) || (x < 10) <- always true - { "(", First, "<|<=", "||", First, ">|>=", ")", More, true }, // (x < 10) || (x > 3) <- always true - { "(", Second, "<|<=", "||", First, "<|<=", ")", Less, true }, // (3 < x) || (x < 10) <- always true - { "(", First, "<|<=", "||", Second, "<|<=", ")", More, true }, // (x < 10) || (3 < x) <- always true - { "(", First, ">|>=", "||", Second, ">|>=", ")", Less, true }, // (x > 3) || (10 > x) <- always true - { "(", Second, ">|>=", "||", First, ">|>=", ")", More, true }, // (10 > x) || (x > 3) <- always true - { "(", Second, "<|<=", "||", Second, ">|<=", ")", Less, true }, // (3 < x) || (10 > x) <- always true - { "(", Second, ">|>=", "||", Second, "<|<=", ")", More, true }, // (10 > x) || (3 < x) <- always true - }; - - for (unsigned int i = 0; i < (sizeof(conditions) / sizeof(conditions[0])); i++) { - if (!((conditions[i].position1 == NA) || (((conditions[i].position1 == First) && varFirst1) || ((conditions[i].position1 == Second) && !varFirst1)))) - continue; - - if (!((conditions[i].position2 == NA) || (((conditions[i].position2 == First) && varFirst2) || ((conditions[i].position2 == Second) && !varFirst2)))) - continue; - - if (!Token::Match(op1Tok, conditions[i].op1TokStr)) - continue; - - if (!Token::Match(op2Tok, conditions[i].op2TokStr)) - continue; - - if (!Token::Match(op3Tok, conditions[i].op3TokStr)) - continue; - - if (!Token::Match(logicTok->previous(), conditions[i].before)) - continue; - - if (!Token::Match(nextTok, conditions[i].after)) - continue; - - if ((conditions[i].relation == Equal && MathLib::isEqual(firstConstant, secondConstant)) || - (conditions[i].relation == NotEqual && MathLib::isNotEqual(firstConstant, secondConstant)) || - (conditions[i].relation == Less && MathLib::isLess(firstConstant, secondConstant)) || - (conditions[i].relation == LessEqual && MathLib::isLessEqual(firstConstant, secondConstant)) || - (conditions[i].relation == More && MathLib::isGreater(firstConstant, secondConstant)) || - (conditions[i].relation == MoreEqual && MathLib::isGreaterEqual(firstConstant, secondConstant))) - incorrectLogicOperatorError(term1Tok, conditions[i].state); - } - } - - tok = Token::findmatch(endTok->next(), conditionPattern); - endTok = tok ? tok->next()->link() : NULL; - } -} - -//--------------------------------------------------------------------------- -// try {} catch (std::exception err) {} <- Should be "std::exception& err" -//--------------------------------------------------------------------------- -void CheckOther::checkCatchExceptionByValue() -{ - if (!_settings->isEnabled("style")) - return; - - const char catchPattern[] = "} catch ("; - const Token *tok = Token::findmatch(_tokenizer->tokens(), catchPattern); - const Token *endTok = tok ? tok->tokAt(2)->link() : NULL; - - while (tok && endTok) { - // Find a pass-by-value declaration in the catch(), excluding basic types - // e.g. catch (std::exception err) - const Token *tokType = Token::findmatch(tok, "%type% %var% )", endTok); - if (tokType && !tokType->isStandardType()) { - catchExceptionByValueError(tokType); - } - - tok = Token::findmatch(endTok->next(), catchPattern); - endTok = tok ? tok->tokAt(2)->link() : NULL; - } -} - -//--------------------------------------------------------------------------- -// strtol(str, 0, radix) <- radix must be 0 or 2-36 -//--------------------------------------------------------------------------- - -void CheckOther::invalidFunctionUsage() -{ - // strtol and strtoul.. - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (!Token::Match(tok, "strtol|strtoul (")) - continue; - - // Locate the third parameter of the function call.. - int param = 1; - for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) { - if (tok2->str() == "(") - tok2 = tok2->link(); - else if (tok2->str() == ")") - break; - else if (tok2->str() == ",") { - ++param; - if (param == 3) { - if (Token::Match(tok2, ", %num% )")) { - const MathLib::bigint radix = MathLib::toLongNumber(tok2->next()->str()); - if (!(radix == 0 || (radix >= 2 && radix <= 36))) { - dangerousUsageStrtolError(tok2); - } - } - break; - } - } - } - } - - // sprintf|snprintf overlapping data - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - // Get variable id of target buffer.. - unsigned int varid = 0; - - if (Token::Match(tok, "sprintf|snprintf ( %var% ,")) - varid = tok->tokAt(2)->varId(); - - else if (Token::Match(tok, "sprintf|snprintf ( %var% . %var% ,")) - varid = tok->tokAt(4)->varId(); - - if (varid == 0) - continue; - - // goto "," - const Token *tok2 = tok->tokAt(3); - while (tok2 && tok2->str() != ",") - tok2 = tok2->next(); - if (!tok2) - continue; - - // is any source buffer overlapping the target buffer? - int parlevel = 0; - while ((tok2 = tok2->next()) != NULL) { - if (tok2->str() == "(") - ++parlevel; - else if (tok2->str() == ")") { - --parlevel; - if (parlevel < 0) - break; - } else if (parlevel == 0 && Token::Match(tok2, ", %varid% [,)]", varid)) { - sprintfOverlappingDataError(tok2->next(), tok2->next()->str()); - break; - } - } - } -} -//--------------------------------------------------------------------------- - -void CheckOther::invalidScanf() -{ - if (!_settings->isEnabled("style")) - return; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - const Token *formatToken = 0; - if (Token::Match(tok, "scanf|vscanf ( %str% ,")) - formatToken = tok->tokAt(2); - else if (Token::Match(tok, "fscanf|vfscanf ( %var% , %str% ,")) - formatToken = tok->tokAt(4); - else - continue; - - bool format = false; - - // scan the string backwards, so we don't need to keep states - const std::string &formatstr(formatToken->str()); - for (unsigned int i = 1; i < formatstr.length(); i++) { - if (formatstr[i] == '%') - format = !format; - - else if (!format) - continue; - - else if (std::isdigit(formatstr[i])) { - format = false; - } - - else if (std::isalpha(formatstr[i])) { - invalidScanfError(tok); - format = false; - } - } - } -} - -//--------------------------------------------------------------------------- -// if (!x==3) <- Probably meant to be "x!=3" -//--------------------------------------------------------------------------- -void CheckOther::checkComparisonOfBoolWithInt() -{ - if (!_settings->isEnabled("style")) - return; - - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "( ! %var% ==|!= %num% )")) { - const Token *numTok = tok->tokAt(4); - if (numTok && numTok->str() != "0") { - comparisonOfBoolWithIntError(numTok, tok->strAt(2)); - } - } else if (Token::Match(tok, "( %num% ==|!= ! %var% )")) { - const Token *numTok = tok->tokAt(1); - if (numTok && numTok->str() != "0") { - comparisonOfBoolWithIntError(numTok, tok->strAt(4)); - } - } - } -} - -//--------------------------------------------------------------------------- -// switch (x) -// { -// case 2: -// y = a; -// break; -// break; // <- Redundant break -// case 3: -// y = b; -// } -//--------------------------------------------------------------------------- -void CheckOther::checkDuplicateBreak() -{ - if (!_settings->isEnabled("style")) - return; - - const char breakPattern[] = "break|continue ; break|continue ;"; - - // Find consecutive break or continue statements. e.g.: - // break; break; - const Token *tok = Token::findmatch(_tokenizer->tokens(), breakPattern); - while (tok) { - duplicateBreakError(tok); - tok = Token::findmatch(tok->next(), breakPattern); - } -} - - -void CheckOther::sizeofForNumericParameterError(const Token *tok) -{ - reportError(tok, Severity::error, - "sizeofwithnumericparameter", "Using sizeof with a numeric constant as function " - "argument might not be what you intended.\n" - "It is unusual to use constant value with sizeof. For example, this code:\n" - " int f() {\n" - " return sizeof(10);\n" - " }\n" - " returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10." - ); -} - -void CheckOther::sizeofForArrayParameterError(const Token *tok) -{ - reportError(tok, Severity::error, - "sizeofwithsilentarraypointer", "Using sizeof for array given as function argument " - "returns the size of pointer.\n" - "Giving array as function parameter and then using sizeof-operator for the array " - "argument. In this case the sizeof-operator returns the size of pointer (in the " - "system). It does not return the size of the whole array in bytes as might be " - "expected. For example, this code:\n" - " int f(char a[100]) {\n" - " return sizeof(a);\n" - " }\n" - " returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the " - "size of the array in bytes)." - ); -} - -void CheckOther::invalidScanfError(const Token *tok) -{ - reportError(tok, Severity::warning, - "invalidscanf", "scanf without field width limits can crash with huge input data\n" - "scanf without field width limits can crash with huge input data. To fix this error " - "message add a field width specifier:\n" - " %s => %20s\n" - " %i => %3i\n" - "\n" - "Sample program that can crash:\n" - "\n" - "#include \n" - "int main()\n" - "{\n" - " int a;\n" - " scanf(\"%i\", &a);\n" - " return 0;\n" - "}\n" - "\n" - "To make it crash:\n" - "perl -e 'print \"5\"x2100000' | ./a.out"); -} - -//--------------------------------------------------------------------------- -// Check for unsigned divisions -//--------------------------------------------------------------------------- - -void CheckOther::checkUnsignedDivision() -{ - if (!_settings->isEnabled("style")) - return; - - // Check for "ivar / uvar" and "uvar / ivar" - std::map varsign; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "[{};(,] %type% %var% [;=,)]")) { - if (tok->tokAt(1)->isUnsigned()) - varsign[tok->tokAt(2)->varId()] = 'u'; - else - varsign[tok->tokAt(2)->varId()] = 's'; - } - - else if (!Token::Match(tok, "[).]") && Token::Match(tok->next(), "%var% / %num%")) { - if (tok->strAt(3)[0] == '-') { - char sign1 = varsign[tok->tokAt(1)->varId()]; - if (sign1 == 'u') { - udivError(tok->next()); - } - } - } - - else if (Token::Match(tok, "(|[|=|%op% %num% / %var%")) { - if (tok->strAt(1)[0] == '-') { - char sign2 = varsign[tok->tokAt(3)->varId()]; - if (sign2 == 'u') { - udivError(tok->next()); - } - } - } - } -} - -//--------------------------------------------------------------------------- -// memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted -//--------------------------------------------------------------------------- -void CheckOther::checkMemsetZeroBytes() -{ - const Token *tok = _tokenizer->tokens(); - while (tok && ((tok = Token::findmatch(tok, "memset ( %var% , %num% , 0 )")) != NULL)) { - memsetZeroBytesError(tok, tok->strAt(2)); - tok = tok->tokAt(8); - } -} -//--------------------------------------------------------------------------- - - - -//--------------------------------------------------------------------------- -// Usage of function variables -//--------------------------------------------------------------------------- - -/** - * @brief This class is used to capture the control flow within a function. - */ -class ScopeInfo { -public: - ScopeInfo() : _token(NULL), _parent(NULL) {} - ScopeInfo(const Token *token, ScopeInfo *parent_) : _token(token), _parent(parent_) {} - ~ScopeInfo(); - - ScopeInfo *parent() { - return _parent; - } - ScopeInfo *addChild(const Token *token); - void remove(ScopeInfo *scope); - -private: - const Token *_token; - ScopeInfo *_parent; - std::list _children; -}; - -ScopeInfo::~ScopeInfo() -{ - while (!_children.empty()) { - delete *_children.begin(); - _children.pop_front(); - } -} - -ScopeInfo *ScopeInfo::addChild(const Token *token) -{ - ScopeInfo *temp = new ScopeInfo(token, this); - - _children.push_back(temp); - - return temp; -} - -void ScopeInfo::remove(ScopeInfo *scope) -{ - std::list::iterator it; - - for (it = _children.begin(); it != _children.end(); ++it) { - if (*it == scope) { - delete *it; - _children.erase(it); - break; - } - } -} - -/** - * @brief This class is used create a list of variables within a function. - */ -class Variables { -public: - enum VariableType { standard, array, pointer, reference, pointerArray, referenceArray, pointerPointer }; - - /** Store information about variable usage */ - class VariableUsage { - public: - VariableUsage(const Token *name = 0, - VariableType type = standard, - ScopeInfo *scope = NULL, - bool read = false, - bool write = false, - bool modified = false, - bool allocateMemory = false) : - _name(name), - _type(type), - _scope(scope), - _read(read), - _write(write), - _modified(modified), - _allocateMemory(allocateMemory) {} - - /** variable is used.. set both read+write */ - void use() { - _read = true; - _write = true; - } - - /** is variable unused? */ - bool unused() const { - return (!_read && !_write); - } - - const Token *_name; - VariableType _type; - ScopeInfo *_scope; - bool _read; - bool _write; - bool _modified; // read/modify/write - bool _allocateMemory; - std::set _aliases; - std::set _assignments; - }; - - typedef std::map VariableMap; - - void clear() { - _varUsage.clear(); - } - VariableMap &varUsage() { - return _varUsage; - } - void addVar(const Token *name, VariableType type, ScopeInfo *scope, bool write_); - void allocateMemory(unsigned int varid); - void read(unsigned int varid); - void readAliases(unsigned int varid); - void readAll(unsigned int varid); - void write(unsigned int varid); - void writeAliases(unsigned int varid); - void writeAll(unsigned int varid); - void use(unsigned int varid); - void modified(unsigned int varid); - VariableUsage *find(unsigned int varid); - void alias(unsigned int varid1, unsigned int varid2, bool replace); - void erase(unsigned int varid) { - _varUsage.erase(varid); - } - void eraseAliases(unsigned int varid); - void eraseAll(unsigned int varid); - void clearAliases(unsigned int varid); - -private: - VariableMap _varUsage; -}; - -/** - * Alias the 2 given variables. Either replace the existing aliases if - * they exist or merge them. You would replace an existing alias when this - * assignment is in the same scope as the previous assignment. You might - * merge the aliases when this assignment is in a different scope from the - * previous assignment depending on the relationship of the 2 scopes. - */ -void Variables::alias(unsigned int varid1, unsigned int varid2, bool replace) -{ - VariableUsage *var1 = find(varid1); - VariableUsage *var2 = find(varid2); - - // alias to self - if (varid1 == varid2) { - if (var1) - var1->use(); - return; - } - - std::set::iterator i; - - if (replace) { - // remove var1 from all aliases - for (i = var1->_aliases.begin(); i != var1->_aliases.end(); ++i) { - VariableUsage *temp = find(*i); - - if (temp) - temp->_aliases.erase(var1->_name->varId()); - } - - // remove all aliases from var1 - var1->_aliases.clear(); - } - - // var1 gets all var2s aliases - for (i = var2->_aliases.begin(); i != var2->_aliases.end(); ++i) { - if (*i != varid1) - var1->_aliases.insert(*i); - } - - // var2 is an alias of var1 - var2->_aliases.insert(varid1); - var1->_aliases.insert(varid2); - - if (var2->_type == Variables::pointer) - var2->_read = true; -} - -void Variables::clearAliases(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - // remove usage from all aliases - std::set::iterator i; - - for (i = usage->_aliases.begin(); i != usage->_aliases.end(); ++i) { - VariableUsage *temp = find(*i); - - if (temp) - temp->_aliases.erase(usage->_name->varId()); - } - - // remove all aliases from usage - usage->_aliases.clear(); - } -} - -void Variables::eraseAliases(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) - erase(*aliases); - } -} - -void Variables::eraseAll(unsigned int varid) -{ - eraseAliases(varid); - erase(varid); -} - -void Variables::addVar(const Token *name, - VariableType type, - ScopeInfo *scope, - bool write_) -{ - if (name->varId() > 0) - _varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, scope, false, write_, false))); -} - -void Variables::allocateMemory(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) - usage->_allocateMemory = true; -} - -void Variables::read(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) - usage->_read = true; -} - -void Variables::readAliases(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) { - VariableUsage *aliased = find(*aliases); - - if (aliased) - aliased->_read = true; - } - } -} - -void Variables::readAll(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - usage->_read = true; - - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) { - VariableUsage *aliased = find(*aliases); - - if (aliased) - aliased->_read = true; - } - } -} - -void Variables::write(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) - usage->_write = true; -} - -void Variables::writeAliases(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) { - VariableUsage *aliased = find(*aliases); - - if (aliased) - aliased->_write = true; - } - } -} - -void Variables::writeAll(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - usage->_write = true; - - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) { - VariableUsage *aliased = find(*aliases); - - if (aliased) - aliased->_write = true; - } - } -} - -void Variables::use(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - usage->use(); - - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) { - VariableUsage *aliased = find(*aliases); - - if (aliased) - aliased->use(); - } - } -} - -void Variables::modified(unsigned int varid) -{ - VariableUsage *usage = find(varid); - - if (usage) { - usage->_modified = true; - - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) { - VariableUsage *aliased = find(*aliases); - - if (aliased) - aliased->_modified = true; - } - } -} - -Variables::VariableUsage *Variables::find(unsigned int varid) -{ - if (varid) { - VariableMap::iterator i = _varUsage.find(varid); - if (i != _varUsage.end()) - return &i->second; - } - return 0; -} - -static int doAssignment(Variables &variables, const Token *tok, bool dereference, ScopeInfo *scope) -{ - int next = 0; - - // a = a + b; - if (Token::Match(tok, "%var% = %var% !!;") && tok->str() == tok->strAt(2)) { - return 2; - } - - // check for aliased variable - const unsigned int varid1 = tok->varId(); - Variables::VariableUsage *var1 = variables.find(varid1); - - if (var1) { - int start = 1; - - // search for '=' - while (tok->tokAt(start)->str() != "=") - start++; - - start++; - - if (Token::Match(tok->tokAt(start), "&| %var%") || - Token::Match(tok->tokAt(start), "( const| struct|union| %type% *| ) &| %var%") || - Token::Match(tok->tokAt(start), "( const| struct|union| %type% *| ) ( &| %var%") || - Token::Match(tok->tokAt(start), "%any% < const| struct|union| %type% *| > ( &| %var%")) { - unsigned char offset = 0; - unsigned int varid2; - bool addressOf = false; - - if (Token::Match(tok->tokAt(start), "%var% .")) - variables.use(tok->tokAt(start)->varId()); // use = read + write - - // check for C style cast - if (tok->tokAt(start)->str() == "(") { - if (tok->tokAt(start + 1)->str() == "const") - offset++; - - if (Token::Match(tok->tokAt(start + 1 + offset), "struct|union")) - offset++; - - if (tok->tokAt(start + 2 + offset)->str() == "*") - offset++; - - if (tok->tokAt(start + 3 + offset)->str() == "&") { - addressOf = true; - next = start + 4 + offset; - } else if (tok->tokAt(start + 3 + offset)->str() == "(") { - if (tok->tokAt(start + 4 + offset)->str() == "&") { - addressOf = true; - next = start + 5 + offset; - } else - next = start + 4 + offset; - } else - next = start + 3 + offset; - } - - // check for C++ style cast - else if (tok->tokAt(start)->str().find("cast") != std::string::npos && - tok->tokAt(start + 1)->str() == "<") { - if (tok->tokAt(start + 2)->str() == "const") - offset++; - - if (Token::Match(tok->tokAt(start + 2 + offset), "struct|union")) - offset++; - - if (tok->tokAt(start + 3 + offset)->str() == "*") - offset++; - - if (tok->tokAt(start + 5 + offset)->str() == "&") { - addressOf = true; - next = start + 6 + offset; - } else - next = start + 5 + offset; - } - - // check for var ? ... - else if (Token::Match(tok->tokAt(start), "%var% ?")) { - next = start; - } - - // no cast - else { - if (tok->tokAt(start)->str() == "&") { - addressOf = true; - next = start + 1; - } else if (tok->tokAt(start)->str() == "new") - return 0; - else - next = start; - } - - // check if variable is local - varid2 = tok->tokAt(next)->varId(); - Variables::VariableUsage *var2 = variables.find(varid2); - - if (var2) { // local variable (alias or read it) - if (var1->_type == Variables::pointer) { - if (dereference) - variables.read(varid2); - else { - if (addressOf || - var2->_type == Variables::array || - var2->_type == Variables::pointer) { - bool replace = true; - - // check if variable declared in same scope - if (scope == var1->_scope) - replace = true; - - // not in same scope as declaration - else { - std::set::iterator assignment; - - // check for an assignment in this scope - assignment = var1->_assignments.find(scope); - - // no other assignment in this scope - if (assignment == var1->_assignments.end()) { - // nothing to replace - if (var1->_assignments.empty()) - replace = false; - - // this variable has previous assignments - else { - /** - * @todo determine if existing aliases should be replaced or merged - */ - - replace = false; - } - } - - // assignment in this scope - else { - // replace when only one other assignment - if (var1->_assignments.size() == 1) - replace = true; - - // otherwise, merge them - else - replace = false; - } - } - - variables.alias(varid1, varid2, replace); - } else if (tok->tokAt(next + 1)->str() == "?") { - if (var2->_type == Variables::reference) - variables.readAliases(varid2); - else - variables.read(varid2); - } - } - } else if (var1->_type == Variables::reference) { - variables.alias(varid1, varid2, true); - } else { - if (var2->_type == Variables::pointer && tok->tokAt(next + 1)->str() == "[") - variables.readAliases(varid2); - - variables.read(varid2); - } - } else { // not a local variable (or an unsupported local variable) - if (var1->_type == Variables::pointer && !dereference) { - // check if variable declaration is in this scope - if (var1->_scope == scope) - variables.clearAliases(varid1); - else { - std::set::iterator assignment; - - // check for an assignment in this scope - assignment = var1->_assignments.find(scope); - - // no other assignment in this scope - if (assignment == var1->_assignments.end()) { - /** - * @todo determine if existing aliases should be discarded - */ - } - - // this assignment replaces the last assignment in this scope - else { - // aliased variables in a larger scope are not supported - // remove all aliases - variables.clearAliases(varid1); - } - } - } - } - } - - var1->_assignments.insert(scope); - } - - // check for alias to struct member - // char c[10]; a.b = c; - else if (Token::Match(tok->tokAt(-2), "%var% .")) { - if (Token::Match(tok->tokAt(2), "%var%")) { - unsigned int varid2 = tok->tokAt(2)->varId(); - Variables::VariableUsage *var2 = variables.find(varid2); - - // struct member aliased to local variable - if (var2 && (var2->_type == Variables::array || - var2->_type == Variables::pointer)) { - // erase aliased variable and all variables that alias it - // to prevent false positives - variables.eraseAll(varid2); - } - } - } - - return next; -} - -static bool nextIsStandardType(const Token *tok) -{ - tok = tok->next(); - - if (tok->str() == "static") - tok = tok->next(); - - return tok->isStandardType(); -} - -static bool nextIsStandardTypeOrVoid(const Token *tok) -{ - tok = tok->next(); - - if (tok->str() == "static") - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - return tok->isStandardType() || tok->str() == "void"; -} - -bool CheckOther::isRecordTypeWithoutSideEffects(const Token *tok) -{ - const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok->varId()); - - // a type that has no side effects (no constructors and no members with constructors) - /** @todo false negative: check base class for side effects */ - /** @todo false negative: check constructors for side effects */ - if (var && var->type() && var->type()->numConstructors == 0 && - (var->type()->varlist.empty() || var->type()->needInitialization == Scope::True) && - var->type()->derivedFrom.empty()) - return true; - - return false; -} - -void CheckOther::functionVariableUsage() -{ - if (!_settings->isEnabled("style")) - return; - - // Parse all executing scopes.. - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - - std::list::const_iterator scope; - - for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - // only check functions - if (scope->type != Scope::eFunction) - continue; - - // First token for the current scope.. - const Token *const tok1 = scope->classStart; - - // varId, usage {read, write, modified} - Variables variables; - - // scopes - ScopeInfo scopes; - ScopeInfo *info = &scopes; - - unsigned int indentlevel = 0; - for (const Token *tok = tok1; tok; tok = tok->next()) { - if (tok->str() == "{") { - // replace the head node when found - if (indentlevel == 0) - scopes = ScopeInfo(tok, NULL); - // add the new scope - else - info = info->addChild(tok); - ++indentlevel; - } else if (tok->str() == "}") { - --indentlevel; - - info = info->parent(); - - if (indentlevel == 0) - break; - } else if (Token::Match(tok, "struct|union|class {") || - Token::Match(tok, "struct|union|class %type% {|:")) { - while (tok->str() != "{") - tok = tok->next(); - tok = tok->link(); - if (!tok) - break; - } - - if (Token::Match(tok, "[;{}] asm ( ) ;")) { - variables.clear(); - break; - } - - // standard type declaration with possible initialization - // int i; int j = 0; static int k; - if (Token::Match(tok, "[;{}] static| %type% %var% ;|=") && - !Token::Match(tok->next(), "return|throw")) { - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - if (tok->isStandardType() || isRecordTypeWithoutSideEffects(tok->next())) { - variables.addVar(tok->next(), Variables::standard, info, - tok->tokAt(2)->str() == "=" || isStatic); - } - tok = tok->next(); - } - - // standard const type declaration - // const int i = x; - else if (Token::Match(tok, "[;{}] const %type% %var% =")) { - tok = tok->next()->next(); - - if (tok->isStandardType() || isRecordTypeWithoutSideEffects(tok->next())) - variables.addVar(tok->next(), Variables::standard, info, true); - - tok = tok->next(); - } - - // std::string declaration with possible initialization - // std::string s; std::string s = "string"; - else if (Token::Match(tok, "[;{}] static| std :: string %var% ;|=")) { - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - tok = tok->tokAt(3); - variables.addVar(tok, Variables::standard, info, - tok->next()->str() == "=" || isStatic); - } - - // standard struct type declaration with possible initialization - // struct S s; struct S s = { 0 }; static struct S s; - else if (Token::Match(tok, "[;{}] static| struct %type% %var% ;|=") && - (isRecordTypeWithoutSideEffects(tok->strAt(1) == "static" ? tok->tokAt(4) : tok->tokAt(3)))) { - tok = tok->next(); - - bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - tok = tok->next(); - - variables.addVar(tok->next(), Variables::standard, info, - tok->tokAt(2)->str() == "=" || isStatic); - tok = tok->next(); - } - - // standard type declaration and initialization using constructor - // int i(0); static int j(0); - else if (Token::Match(tok, "[;{}] static| %type% %var% ( %any% ) ;") && - nextIsStandardType(tok)) { - tok = tok->next(); - - if (tok->str() == "static") - tok = tok->next(); - - variables.addVar(tok->next(), Variables::standard, info, true); - - // check if a local variable is used to initialize this variable - if (tok->tokAt(3)->varId() > 0) - variables.readAll(tok->tokAt(3)->varId()); - tok = tok->tokAt(4); - } - - // standard type declaration of array of with possible initialization - // int i[10]; int j[2] = { 0, 1 }; static int k[2] = { 2, 3 }; - else if (Token::Match(tok, "[;{}] static| const| %type% *| %var% [ %any% ] ;|=") && - nextIsStandardType(tok)) { - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - if (tok->str() != "return" && tok->str() != "throw") { - bool isPointer = bool(tok->strAt(1) == "*"); - const Token * const nametok = tok->tokAt(isPointer ? 2 : 1); - - variables.addVar(nametok, isPointer ? Variables::pointerArray : Variables::array, info, - nametok->tokAt(4)->str() == "=" || isStatic); - - // check for reading array size from local variable - if (nametok->tokAt(2)->varId() != 0) - variables.read(nametok->tokAt(2)->varId()); - - // look at initializers - if (Token::simpleMatch(nametok->tokAt(4), "= {")) { - tok = nametok->tokAt(6); - while (tok->str() != "}") { - if (Token::Match(tok, "%var%")) - variables.read(tok->varId()); - tok = tok->next(); - } - } else - tok = nametok->tokAt(3); - } - } - - // pointer or reference declaration with possible initialization - // int * i; int * j = 0; static int * k = 0; - else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% ;|=")) { - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - if (tok->strAt(1) == "::") - tok = tok->tokAt(2); - - if (tok->str() != "return" && tok->str() != "throw") { - Variables::VariableType type; - - if (tok->next()->str() == "*") - type = Variables::pointer; - else - type = Variables::reference; - - bool written = tok->tokAt(3)->str() == "="; - - variables.addVar(tok->tokAt(2), type, info, written || isStatic); - - int offset = 0; - - // check for assignment - if (written) - offset = doAssignment(variables, tok->tokAt(2), false, info); - - tok = tok->tokAt(2 + offset); - } - } - - // pointer to pointer declaration with possible initialization - // int ** i; int ** j = 0; static int ** k = 0; - else if (Token::Match(tok, "[;{}] static| const| %type% * * %var% ;|=")) { - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - if (tok->str() != "return") { - bool written = tok->tokAt(4)->str() == "="; - - variables.addVar(tok->tokAt(3), Variables::pointerPointer, info, written || isStatic); - - int offset = 0; - - // check for assignment - if (written) - offset = doAssignment(variables, tok->tokAt(3), false, info); - - tok = tok->tokAt(3 + offset); - } - } - - // pointer or reference of struct or union declaration with possible initialization - // struct s * i; struct s * j = 0; static struct s * k = 0; - else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% ;|=")) { - Variables::VariableType type; - - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - if (tok->strAt(2) == "*") - type = Variables::pointer; - else - type = Variables::reference; - - const bool written = tok->strAt(4) == "="; - - variables.addVar(tok->tokAt(3), type, info, written || isStatic); - - int offset = 0; - - // check for assignment - if (written) - offset = doAssignment(variables, tok->tokAt(3), false, info); - - tok = tok->tokAt(3 + offset); - } - - // pointer or reference declaration with initialization using constructor - // int * i(j); int * k(i); static int * l(i); - else if (Token::Match(tok, "[;{}] static| const| %type% &|* %var% ( %any% ) ;") && - nextIsStandardTypeOrVoid(tok)) { - Variables::VariableType type; - - tok = tok->next(); - - if (tok->str() == "static") - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - if (tok->next()->str() == "*") - type = Variables::pointer; - else - type = Variables::reference; - - unsigned int varid = 0; - - // check for aliased variable - if (Token::Match(tok->tokAt(4), "%var%")) - varid = tok->tokAt(4)->varId(); - - variables.addVar(tok->tokAt(2), type, info, true); - - // check if a local variable is used to initialize this variable - if (varid > 0) { - Variables::VariableUsage *var = variables.find(varid); - - if (type == Variables::pointer) { - variables.use(tok->tokAt(4)->varId()); - - if (var && (var->_type == Variables::array || - var->_type == Variables::pointer)) - var->_aliases.insert(tok->varId()); - } else { - variables.readAll(tok->tokAt(4)->varId()); - if (var) - var->_aliases.insert(tok->varId()); - } - } - tok = tok->tokAt(5); - } - - // array of pointer or reference declaration with possible initialization - // int * p[10]; int * q[10] = { 0 }; static int * * r[10] = { 0 }; - else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% [ %any% ] ;|=")) { - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - if (tok->str() != "return") { - variables.addVar(tok->tokAt(2), - tok->next()->str() == "*" ? Variables::pointerArray : Variables::referenceArray, info, - tok->tokAt(6)->str() == "=" || isStatic); - - // check for reading array size from local variable - if (tok->tokAt(4)->varId() != 0) - variables.read(tok->tokAt(4)->varId()); - - tok = tok->tokAt(5); - } - } - - // array of pointer or reference of struct or union declaration with possible initialization - // struct S * p[10]; struct T * q[10] = { 0 }; static struct S * r[10] = { 0 }; - else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% [ %any% ] ;|=")) { - tok = tok->next(); - - const bool isStatic = tok->str() == "static"; - if (isStatic) - tok = tok->next(); - - if (tok->str() == "const") - tok = tok->next(); - - variables.addVar(tok->tokAt(3), - tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, info, - tok->tokAt(7)->str() == "=" || isStatic); - - // check for reading array size from local variable - if (tok->tokAt(5)->varId() != 0) - variables.read(tok->tokAt(5)->varId()); - - tok = tok->tokAt(6); - } - - // Freeing memory (not considered "using" the pointer if it was also allocated in this function) - else if (Token::Match(tok, "free|g_free|kfree|vfree ( %var% )") || - Token::Match(tok, "delete %var% ;") || - Token::Match(tok, "delete [ ] %var% ;")) { - unsigned int varid = 0; - if (tok->str() != "delete") { - varid = tok->tokAt(2)->varId(); - tok = tok->tokAt(3); - } else if (tok->strAt(1) == "[") { - varid = tok->tokAt(3)->varId(); - tok = tok->tokAt(4); - } else { - varid = tok->next()->varId(); - tok = tok->tokAt(2); - } - - Variables::VariableUsage *var = variables.find(varid); - if (var && !var->_allocateMemory) { - variables.readAll(varid); - } - } - - else if (Token::Match(tok, "return|throw %var%")) - variables.readAll(tok->next()->varId()); - - // assignment - else if (Token::Match(tok, "*| (| ++|--| %var% ++|--| )| =") || - Token::Match(tok, "*| ( const| %type% *| ) %var% =")) { - bool dereference = false; - bool pre = false; - bool post = false; - - if (tok->str() == "*") { - dereference = true; - tok = tok->next(); - } - - if (Token::Match(tok, "( const| %type% *| ) %var% =")) - tok = tok->link()->next(); - - else if (tok->str() == "(") - tok = tok->next(); - - if (Token::Match(tok, "++|--")) { - pre = true; - tok = tok->next(); - } - - if (Token::Match(tok->next(), "++|--")) - post = true; - - const unsigned int varid1 = tok->varId(); - const Token *start = tok; - - tok = tok->tokAt(doAssignment(variables, tok, dereference, info)); - - if (pre || post) - variables.use(varid1); - - if (dereference) { - Variables::VariableUsage *var = variables.find(varid1); - if (var && var->_type == Variables::array) - variables.write(varid1); - variables.writeAliases(varid1); - variables.read(varid1); - } else { - Variables::VariableUsage *var = variables.find(varid1); - if (var && var->_type == Variables::reference) { - variables.writeAliases(varid1); - variables.read(varid1); - } - // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable - else if (var && var->_type == Variables::pointer && - Token::Match(start, "%var% = new|malloc|calloc|g_malloc|kmalloc|vmalloc")) { - bool allocate = true; - - if (start->strAt(2) == "new") { - // is it a user defined type? - if (!start->tokAt(3)->isStandardType()) { - if (!isRecordTypeWithoutSideEffects(start)) - allocate = false; - } - } - - if (allocate) - variables.allocateMemory(varid1); - else - variables.write(varid1); - } else if (varid1 && Token::Match(tok, "%varid% .", varid1)) { - variables.use(varid1); - } else { - variables.write(varid1); - } - - Variables::VariableUsage *var2 = variables.find(tok->varId()); - if (var2) { - if (var2->_type == Variables::reference) { - variables.writeAliases(tok->varId()); - variables.read(tok->varId()); - } else if (tok->varId() != varid1 && Token::Match(tok, "%var% .")) - variables.read(tok->varId()); - else if (tok->varId() != varid1 && - var2->_type == Variables::standard && - tok->strAt(-1) != "&") - variables.use(tok->varId()); - } - } - - const Token *equal = tok->next(); - - if (Token::Match(tok->next(), "[ %any% ]")) - equal = tok->tokAt(4); - - // checked for chained assignments - if (tok != start && equal->str() == "=") { - Variables::VariableUsage *var = variables.find(tok->varId()); - - if (var && var->_type != Variables::reference) - var->_read = true; - - tok = tok->previous(); - } - } - - // assignment - else if (Token::Match(tok, "%var% [") && Token::simpleMatch(tok->next()->link(), "] =")) { - unsigned int varid = tok->varId(); - const Variables::VariableUsage *var = variables.find(varid); - - if (var) { - // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable - if (var->_type == Variables::pointer && - Token::Match(tok->next()->link(), "] = new|malloc|calloc|g_malloc|kmalloc|vmalloc")) { - variables.allocateMemory(varid); - } else if (var->_type == Variables::pointer || var->_type == Variables::reference) { - variables.read(varid); - variables.writeAliases(varid); - } else - variables.writeAll(varid); - } - } - - else if (Token::Match(tok, ">>|& %var%")) - variables.use(tok->next()->varId()); // use = read + write - else if (Token::Match(tok, "[;{}] %var% >>")) - variables.use(tok->next()->varId()); // use = read + write - - // function parameter - else if (Token::Match(tok, "[(,] %var% [")) - variables.use(tok->next()->varId()); // use = read + write - else if (Token::Match(tok, "[(,] %var% [,)]") && tok->previous()->str() != "*") - variables.use(tok->next()->varId()); // use = read + write - else if (Token::Match(tok, "[(,] (") && - Token::Match(tok->next()->link(), ") %var% [,)]")) - variables.use(tok->next()->link()->next()->varId()); // use = read + write - - // function - else if (Token::Match(tok, "%var% (")) { - variables.read(tok->varId()); - if (Token::Match(tok->tokAt(2), "%var% =")) - variables.read(tok->tokAt(2)->varId()); - } - - else if (Token::Match(tok, "[{,] %var% [,}]")) - variables.read(tok->next()->varId()); - - else if (Token::Match(tok, "%var% .")) - variables.use(tok->varId()); // use = read + write - - else if ((Token::Match(tok, "[(=&!]") || tok->isExtendedOp()) && - (Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new"))) - variables.readAll(tok->next()->varId()); - - else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || tok->next()->isExtendedOp())) - variables.readAll(tok->varId()); - - else if (Token::Match(tok, "; %var% ;")) - variables.readAll(tok->next()->varId()); - - if (Token::Match(tok, "++|-- %var%")) { - if (tok->strAt(-1) != ";") - variables.use(tok->next()->varId()); - else - variables.modified(tok->next()->varId()); - } - - else if (Token::Match(tok, "%var% ++|--")) { - if (tok->strAt(-1) != ";") - variables.use(tok->varId()); - else - variables.modified(tok->varId()); - } - - else if (tok->isAssignmentOp()) { - for (const Token *tok2 = tok->next(); tok2 && tok2->str() != ";"; tok2 = tok2->next()) { - if (tok2->varId()) { - variables.read(tok2->varId()); - if (tok2->next()->isAssignmentOp()) - variables.write(tok2->varId()); - } - } - } - } - - // Check usage of all variables in the current scope.. - Variables::VariableMap::const_iterator it; - for (it = variables.varUsage().begin(); it != variables.varUsage().end(); ++it) { - const Variables::VariableUsage &usage = it->second; - const std::string &varname = usage._name->str(); - - // variable has been marked as unused so ignore it - if (usage._name->isUnused()) - continue; - - // skip things that are only partially implemented to prevent false positives - if (usage._type == Variables::pointerPointer || - usage._type == Variables::pointerArray || - usage._type == Variables::referenceArray) - continue; - - // variable has had memory allocated for it, but hasn't done - // anything with that memory other than, perhaps, freeing it - if (usage.unused() && !usage._modified && usage._allocateMemory) - allocatedButUnusedVariableError(usage._name, varname); - - // variable has not been written, read, or modified - else if (usage.unused() && !usage._modified) - unusedVariableError(usage._name, varname); - - // variable has not been written but has been modified - else if (usage._modified & !usage._write) - unassignedVariableError(usage._name, varname); - - // variable has been written but not read - else if (!usage._read && !usage._modified) - unreadVariableError(usage._name, varname); - - // variable has been read but not written - else if (!usage._write && !usage._allocateMemory) - unassignedVariableError(usage._name, varname); - } - } -} - -void CheckOther::unusedVariableError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::style, "unusedVariable", "Unused variable: " + varname); -} - -void CheckOther::allocatedButUnusedVariableError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::style, "unusedAllocatedMemory", "Variable '" + varname + "' is allocated memory that is never used"); -} - -void CheckOther::unreadVariableError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::style, "unreadVariable", "Variable '" + varname + "' is assigned a value that is never used"); -} - -void CheckOther::unassignedVariableError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::style, "unassignedVariable", "Variable '" + varname + "' is not assigned a value"); -} -//--------------------------------------------------------------------------- - - - - - -//--------------------------------------------------------------------------- -// Check scope of variables.. -//--------------------------------------------------------------------------- - -void CheckOther::checkVariableScope() -{ - if (!_settings->isEnabled("information")) - return; - - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - - std::list::const_iterator scope; - - for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - // only check functions - if (scope->type != Scope::eFunction) - continue; - - // Walk through all tokens.. - int indentlevel = 0; - for (const Token *tok = scope->classStart; tok; tok = tok->next()) { - // Skip function local class and struct declarations.. - if ((tok->str() == "class") || (tok->str() == "struct") || (tok->str() == "union")) { - for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) { - if (tok2->str() == "{") { - tok = tok2->link(); - break; - } - if (Token::Match(tok2, "[,);]")) { - break; - } - } - if (!tok) - break; - } - - else if (tok->str() == "{") { - ++indentlevel; - } else if (tok->str() == "}") { - --indentlevel; - if (indentlevel == 0) - break; - } - - if (indentlevel > 0 && Token::Match(tok, "[{};]")) { - // First token of statement.. - const Token *tok1 = tok->next(); - if (!tok1) - continue; - - if ((tok1->str() == "return") || - (tok1->str() == "throw") || - (tok1->str() == "delete") || - (tok1->str() == "goto") || - (tok1->str() == "else")) - continue; - - // Variable declaration? - if (Token::Match(tok1, "%type% %var% ; %var% = %num% ;")) { - // Tokenizer modify "int i = 0;" to "int i; i = 0;", - // so to handle this situation we just skip - // initialization (see ticket #272). - const unsigned int firstVarId = tok1->next()->varId(); - const unsigned int secondVarId = tok1->tokAt(3)->varId(); - if (firstVarId > 0 && firstVarId == secondVarId) { - lookupVar(tok1->tokAt(6), tok1->strAt(1)); - } - } else if (tok1->isStandardType() && Token::Match(tok1, "%type% %var% [;=]")) { - lookupVar(tok1, tok1->strAt(1)); - } - } - } - } - -} -//--------------------------------------------------------------------------- - -void CheckOther::lookupVar(const Token *tok1, const std::string &varname) -{ - const Token *tok = tok1; - - // Skip the variable declaration.. - while (tok && tok->str() != ";") - tok = tok->next(); - - // Check if the variable is used in this indentlevel.. - bool used1 = false; // used in one sub-scope -> reducable - bool used2 = false; // used in more sub-scopes -> not reducable - int indentlevel = 0; - int parlevel = 0; - bool for_or_while = false; // is sub-scope a "for/while/etc". anything that is not "if" - while (tok) { - if (tok->str() == "{") { - if (tok->strAt(-1) == "=") { - if (Token::findmatch(tok, varname.c_str(), tok->link())) { - return; - } - - tok = tok->link(); - } else - ++indentlevel; - } - - else if (tok->str() == "}") { - if (indentlevel == 0) - break; - --indentlevel; - if (indentlevel == 0) { - if (for_or_while && used2) - return; - used2 |= used1; - used1 = false; - } - } - - else if (tok->str() == "(") { - ++parlevel; - } - - else if (tok->str() == ")") { - --parlevel; - } - - // Bail out if references are used - else if (Token::simpleMatch(tok, (std::string("& ") + varname).c_str())) { - return; - } - - else if (tok->str() == varname) { - if (indentlevel == 0) - return; - used1 = true; - if (for_or_while && !Token::simpleMatch(tok->next(), "=")) - used2 = true; - if (used1 && used2) - return; - } - - else if (indentlevel == 0) { - // %unknown% ( %any% ) { - // If %unknown% is anything except if, we assume - // that it is a for or while loop or a macro hiding either one - if (Token::simpleMatch(tok->next(), "(") && - Token::simpleMatch(tok->next()->link(), ") {")) { - if (tok->str() != "if") - for_or_while = true; - } - - else if (Token::simpleMatch(tok, "do {")) - for_or_while = true; - - // possible unexpanded macro hiding for/while.. - else if (tok->str() != "else" && Token::Match(tok->previous(), "[;{}] %type% {")) { - for_or_while = true; - } - - if (parlevel == 0 && (tok->str() == ";")) - for_or_while = false; - } - - tok = tok->next(); - } - - // Warning if this variable: - // * not used in this indentlevel - // * used in lower indentlevel - if (used1 || used2) - variableScopeError(tok1, varname); -} -//--------------------------------------------------------------------------- - - -//--------------------------------------------------------------------------- -// Check for constant function parameters -//--------------------------------------------------------------------------- - -void CheckOther::checkConstantFunctionParameter() -{ - if (!_settings->isEnabled("style")) - return; - - const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase(); - - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - // TODO: False negatives. This pattern only checks for string. - // Investigate if there are other classes in the std - // namespace and add them to the pattern. There are - // streams for example (however it seems strange with - // const stream parameter). - if (Token::Match(tok, "[,(] const std :: string %var% [,)]")) { - passedByValueError(tok, tok->strAt(5)); - } - - else if (Token::Match(tok, "[,(] const std :: %type% < %type% > %var% [,)]")) { - passedByValueError(tok, tok->strAt(8)); - } - - else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% > %var% [,)]")) { - passedByValueError(tok, tok->strAt(10)); - } - - else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% , std :: %type% > %var% [,)]")) { - passedByValueError(tok, tok->strAt(14)); - } - - else if (Token::Match(tok, "[,(] const std :: %type% < %type% , std :: %type% > %var% [,)]")) { - passedByValueError(tok, tok->strAt(12)); - } - - else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% , %type% > %var% [,)]")) { - passedByValueError(tok, tok->strAt(12)); - } - - else if (Token::Match(tok, "[,(] const std :: %type% < %type% , %type% > %var% [,)]")) { - passedByValueError(tok, tok->strAt(10)); - } - - else if (Token::Match(tok, "[,(] const %type% %var% [,)]")) { - // Check if type is a struct or class. - if (symbolDatabase->isClassOrStruct(tok->strAt(2))) { - passedByValueError(tok, tok->strAt(3)); - } - } - } -} -//--------------------------------------------------------------------------- - - -//--------------------------------------------------------------------------- -// Check that all struct members are used -//--------------------------------------------------------------------------- - -void CheckOther::checkStructMemberUsage() -{ - if (!_settings->isEnabled("style")) - return; - - std::string structname; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (tok->fileIndex() != 0) - continue; - - if (Token::Match(tok, "struct|union %type% {")) { - structname.clear(); - if (Token::simpleMatch(tok->previous(), "extern")) - continue; - if ((!tok->previous() || Token::simpleMatch(tok->previous(), ";")) && Token::Match(tok->tokAt(2)->link(), ("} ; " + tok->strAt(1) + " %var% ;").c_str())) - continue; - - structname = tok->strAt(1); - - // Bail out if struct/union contain any functions - for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) { - if (tok2->str() == "(") { - structname.clear(); - break; - } - - if (tok2->str() == "}") - break; - } - - // bail out if struct is inherited - if (!structname.empty() && Token::findmatch(tok, (",|private|protected|public " + structname).c_str())) - structname.clear(); - - // Bail out if some data is casted to struct.. - const std::string s("( struct| " + tok->next()->str() + " * ) & %var% ["); - if (Token::findmatch(tok, s.c_str())) - structname.clear(); - - // Try to prevent false positives when struct members are not used directly. - if (Token::findmatch(tok, (structname + " *").c_str())) - structname.clear(); - else if (Token::findmatch(tok, (structname + " %type% *").c_str())) - structname = ""; - } - - if (tok->str() == "}") - structname.clear(); - - if (!structname.empty() && Token::Match(tok, "[{;]")) { - // Declaring struct variable.. - std::string varname; - - // declaring a POD variable? - if (!tok->next()->isStandardType()) - continue; - - if (Token::Match(tok->next(), "%type% %var% [;[]")) - varname = tok->strAt(2); - else if (Token::Match(tok->next(), "%type% %type% %var% [;[]")) - varname = tok->strAt(3); - else if (Token::Match(tok->next(), "%type% * %var% [;[]")) - varname = tok->strAt(3); - else if (Token::Match(tok->next(), "%type% %type% * %var% [;[]")) - varname = tok->strAt(4); - else - continue; - - // Check if the struct variable is used anywhere in the file - const std::string usagePattern(". " + varname); - bool used = false; - for (const Token *tok2 = _tokenizer->tokens(); tok2; tok2 = tok2->next()) { - if (Token::simpleMatch(tok2, usagePattern.c_str())) { - used = true; - break; - } - } - - if (!used) { - unusedStructMemberError(tok->next(), structname, varname); - } - } - } -} - - - - - -//--------------------------------------------------------------------------- -// Check usage of char variables.. -//--------------------------------------------------------------------------- - -void CheckOther::checkCharVariable() -{ - if (!_settings->isEnabled("style")) - return; - - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - // Declaring the variable.. - if (Token::Match(tok, "[{};(,] const| char *| %var% [;=,)]") || - Token::Match(tok, "[{};(,] const| char %var% [")) { - // goto 'char' token - tok = tok->next(); - if (tok->str() == "const") - tok = tok->next(); - - // Check for unsigned char - if (tok->isUnsigned()) - continue; - - // Set tok to point to the variable name - tok = tok->next(); - const bool isPointer(tok->str() == "*" || tok->strAt(1) == "["); - if (tok->str() == "*") - tok = tok->next(); - - // Check usage of char variable.. - int indentlevel = 0; - for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { - if (tok2->str() == "{") - ++indentlevel; - - else if (tok2->str() == "}") { - --indentlevel; - if (indentlevel <= 0) - break; - } - - if (!isPointer) { - std::string temp = "%var% [ " + tok->str() + " ]"; - if ((tok2->str() != ".") && Token::Match(tok2->next(), temp.c_str())) { - charArrayIndexError(tok2->next()); - break; - } - } - - if (Token::Match(tok2, "[;{}] %var% = %any% [&|] %any% ;")) { - // is the char variable used in the calculation? - if (tok2->tokAt(3)->varId() != tok->varId() && tok2->tokAt(5)->varId() != tok->varId()) - continue; - - // it's ok with a bitwise and where the other operand is 0xff or less.. - if (tok2->strAt(4) == "&") { - if (tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3))) - continue; - if (tok2->tokAt(5)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(5))) - continue; - } - - // is the result stored in a short|int|long? - if (!Token::findmatch(_tokenizer->tokens(), "short|int|long %varid%", tok2->next()->varId())) - continue; - - // This is an error.. - charBitOpError(tok2); - break; - } - - if (isPointer && Token::Match(tok2, "[;{}] %var% = %any% [&|] ( * %varid% ) ;", tok->varId())) { - // it's ok with a bitwise and where the other operand is 0xff or less.. - if (tok2->strAt(4) == "&" && tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3))) - continue; - - // is the result stored in a short|int|long? - if (!Token::findmatch(_tokenizer->tokens(), "short|int|long %varid%", tok2->next()->varId())) - continue; - - // This is an error.. - charBitOpError(tok2); - break; - } - } - } - } -} -//--------------------------------------------------------------------------- - - - - - - -//--------------------------------------------------------------------------- -// Incomplete statement.. -//--------------------------------------------------------------------------- - -void CheckOther::checkIncompleteStatement() -{ - if (!_settings->isEnabled("style")) - return; - - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (tok->str() == "(") { - tok = tok->link(); - if (Token::simpleMatch(tok, ") {") && Token::simpleMatch(tok->next()->link(), "} ;")) - tok = tok->next()->link(); - } - - else if (Token::simpleMatch(tok, "= {")) - tok = tok->next()->link(); - - else if (tok->str() == "{" && Token::Match(tok->tokAt(-2), "%type% %var%")) - tok = tok->link(); - - else if (Token::Match(tok, "[;{}] %str%") || Token::Match(tok, "[;{}] %num%")) { - // bailout if there is a "? :" in this statement - bool bailout = false; - for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) { - if (tok2->str() == "?") - bailout = true; - else if (tok2->str() == ";") - break; - } - if (bailout) - continue; - - constStatementError(tok->next(), tok->next()->isNumber() ? "numeric" : "string"); - } - } -} -//--------------------------------------------------------------------------- - - - - - - -//--------------------------------------------------------------------------- -// str plus char -//--------------------------------------------------------------------------- - -void CheckOther::strPlusChar() -{ - // Don't use this check for Java and C# programs.. - if (_tokenizer->isJavaOrCSharp()) { - return; - } - - bool charVars[10000] = {0}; - - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - // Declaring char variable.. - if (Token::Match(tok, "char|int|short %var% [;=]")) { - unsigned int varid = tok->next()->varId(); - if (varid > 0 && varid < 10000) - charVars[varid] = true; - } - - // - else if (Token::Match(tok, "[=(] %str% + %any%")) { - // char constant.. - const std::string s = tok->strAt(3); - if (s[0] == '\'') - strPlusChar(tok->next()); - - // char variable.. - unsigned int varid = tok->tokAt(3)->varId(); - if (varid > 0 && varid < 10000 && charVars[varid]) - strPlusChar(tok->next()); - } - } -} - -void CheckOther::checkZeroDivision() -{ - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - - if (Token::Match(tok, "/ %num%") && - MathLib::isInt(tok->next()->str()) && - MathLib::toLongNumber(tok->next()->str()) == 0L) { - zerodivError(tok); - } else if (Token::Match(tok, "div|ldiv|lldiv|imaxdiv ( %num% , %num% )") && - MathLib::isInt(tok->tokAt(4)->str()) && - MathLib::toLongNumber(tok->tokAt(4)->str()) == 0L) { - zerodivError(tok); - } - } -} - - -void CheckOther::checkMathFunctions() -{ - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - // case log(-2) - if (tok->varId() == 0 && - Token::Match(tok, "log|log10 ( %num% )") && - MathLib::isNegative(tok->tokAt(2)->str()) && - MathLib::isInt(tok->tokAt(2)->str()) && - MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0) { - mathfunctionCallError(tok); - } - // case log(-2.0) - else if (tok->varId() == 0 && - Token::Match(tok, "log|log10 ( %num% )") && - MathLib::isNegative(tok->tokAt(2)->str()) && - MathLib::isFloat(tok->tokAt(2)->str()) && - MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.) { - mathfunctionCallError(tok); - } - - // case log(0.0) - else if (tok->varId() == 0 && - Token::Match(tok, "log|log10 ( %num% )") && - !MathLib::isNegative(tok->tokAt(2)->str()) && - MathLib::isFloat(tok->tokAt(2)->str()) && - MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.) { - mathfunctionCallError(tok); - } - - // case log(0) - else if (tok->varId() == 0 && - Token::Match(tok, "log|log10 ( %num% )") && - !MathLib::isNegative(tok->tokAt(2)->str()) && - MathLib::isInt(tok->tokAt(2)->str()) && - MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0) { - mathfunctionCallError(tok); - } - // acos( x ), asin( x ) where x is defined for interval [-1,+1], but not beyond - else if (tok->varId() == 0 && - Token::Match(tok, "acos|asin ( %num% )") && - std::fabs(MathLib::toDoubleNumber(tok->tokAt(2)->str())) > 1.0) { - mathfunctionCallError(tok); - } - // sqrt( x ): if x is negative the result is undefined - else if (tok->varId() == 0 && - Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )") && - MathLib::isNegative(tok->tokAt(2)->str())) { - mathfunctionCallError(tok); - } - // atan2 ( x , y): x and y can not be zero, because this is mathematically not defined - else if (tok->varId() == 0 && - Token::Match(tok, "atan2 ( %num% , %num% )") && - MathLib::isNullValue(tok->tokAt(2)->str()) && - MathLib::isNullValue(tok->tokAt(4)->str())) { - mathfunctionCallError(tok, 2); - } - // fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined). - else if (tok->varId() == 0 && - Token::Match(tok, "fmod ( %num% , %num% )") && - MathLib::isNullValue(tok->tokAt(4)->str())) { - mathfunctionCallError(tok, 2); - } - // pow ( x , y) If x is zero, and y is negative --> division by zero - else if (tok->varId() == 0 && - Token::Match(tok, "pow ( %num% , %num% )") && - MathLib::isNullValue(tok->tokAt(2)->str()) && - MathLib::isNegative(tok->tokAt(4)->str())) { - mathfunctionCallError(tok, 2); - } - - } -} - -/** Is there a function with given name? */ -static bool isFunction(const std::string &name, const Token *startToken) -{ - const std::string pattern1(name + " ("); - for (const Token *tok = startToken; tok; tok = tok->next()) { - // skip executable scopes etc - if (tok->str() == "(") { - tok = tok->link(); - if (Token::simpleMatch(tok, ") {")) - tok = tok->next()->link(); - else if (Token::simpleMatch(tok, ") const {")) - tok = tok->tokAt(2)->link(); - } - - // function declaration/implementation found - if ((tok->str() == "*" || (tok->isName() && tok->str().find(":") ==std::string::npos)) - && Token::simpleMatch(tok->next(), pattern1.c_str())) - return true; - } - return false; -} - -void CheckOther::checkMisusedScopedObject() -{ - // Skip this check for .c files - { - const std::string fname = _tokenizer->getFiles()->at(0); - size_t position = fname.rfind("."); - - if (position != std::string::npos) { - const std::string ext = fname.substr(position); - if (ext == ".c" || ext == ".C") - return; - } - } - - const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase(); - - std::list::const_iterator scope; - - for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - // only check functions - if (scope->type != Scope::eFunction) - continue; - - unsigned int depth = 0; - - for (const Token *tok = scope->classStart; tok; tok = tok->next()) { - if (tok->str() == "{") { - ++depth; - } else if (tok->str() == "}") { - --depth; - if (depth == 0) - break; - } - - if (Token::Match(tok, "[;{}] %var% (") - && Token::simpleMatch(tok->tokAt(2)->link(), ") ;") - && symbolDatabase->isClassOrStruct(tok->next()->str()) - && !isFunction(tok->next()->str(), _tokenizer->tokens())) { - tok = tok->next(); - misusedScopeObjectError(tok, tok->str()); - tok = tok->next(); - } - } - } -} - -void CheckOther::checkIncorrectStringCompare() -{ - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, ". substr ( %any% , %num% ) ==|!= %str%")) { - size_t clen = MathLib::toLongNumber(tok->tokAt(5)->str()); - size_t slen = Token::getStrLength(tok->tokAt(8)); - if (clen != slen) { - incorrectStringCompareError(tok->next(), "substr", tok->tokAt(8)->str(), tok->tokAt(5)->str()); - } - } - if (Token::Match(tok, "%str% ==|!= %var% . substr ( %any% , %num% )")) { - size_t clen = MathLib::toLongNumber(tok->tokAt(8)->str()); - size_t slen = Token::getStrLength(tok); - if (clen != slen) { - incorrectStringCompareError(tok->next(), "substr", tok->str(), tok->tokAt(8)->str()); - } - } - } -} - -//----------------------------------------------------------------------------- -// check for duplicate expressions in if statements -// if (a) { } else if (a) { } -//----------------------------------------------------------------------------- - -static const std::string stringifyTokens(const Token *start, const Token *end) -{ - const Token *tok = start; - std::string stringified; - - if (tok->isUnsigned()) - stringified.append("unsigned "); - else if (tok->isSigned()) - stringified.append("signed "); - - if (tok->isLong()) - stringified.append("long "); - - stringified.append(tok->str()); - - while (tok && tok->next() && tok != end) { - if (tok->isUnsigned()) - stringified.append("unsigned "); - else if (tok->isSigned()) - stringified.append("signed "); - - if (tok->isLong()) - stringified.append("long "); - - tok = tok->next(); - stringified.append(" "); - stringified.append(tok->str()); - } - - return stringified; -} - -static bool expressionHasSideEffects(const Token *first, const Token *last) -{ - for (const Token *tok = first; tok != last->next(); tok = tok->next()) { - // check for assignment - if (tok->isAssignmentOp()) - return true; - - // check for inc/dec - else if (Token::Match(tok, "++|--")) - return true; - - // check for function call - else if (Token::Match(tok, "%var% (") && - !(Token::Match(tok, "c_str|string") || tok->isStandardType())) - return true; - } - - return false; -} - -void CheckOther::checkDuplicateIf() -{ - if (!_settings->isEnabled("style")) - return; - - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - - std::list::const_iterator scope; - - for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - // only check functions - if (scope->type != Scope::eFunction) - continue; - - // check all the code in the function for if (...) and else if (...) statements - for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) { - if (Token::simpleMatch(tok, "if (") && tok->strAt(-1) != "else" && - Token::simpleMatch(tok->next()->link(), ") {")) { - std::map expressionMap; - - // get the expression from the token stream - std::string expression = stringifyTokens(tok->tokAt(2), tok->next()->link()->previous()); - - // save the expression and its location - expressionMap.insert(std::make_pair(expression, tok)); - - // find the next else if (...) statement - const Token *tok1 = tok->next()->link()->next()->link(); - - // check all the else if (...) statements - while (Token::simpleMatch(tok1, "} else if (") && - Token::simpleMatch(tok1->tokAt(3)->link(), ") {")) { - // get the expression from the token stream - expression = stringifyTokens(tok1->tokAt(4), tok1->tokAt(3)->link()->previous()); - - // try to look up the expression to check for duplicates - std::map::iterator it = expressionMap.find(expression); - - // found a duplicate - if (it != expressionMap.end()) { - // check for expressions that have side effects and ignore them - if (!expressionHasSideEffects(tok1->tokAt(4), tok1->tokAt(3)->link()->previous())) - duplicateIfError(it->second, tok1->next()); - } - - // not a duplicate expression so save it and its location - else - expressionMap.insert(std::make_pair(expression, tok1->next())); - - // find the next else if (...) statement - tok1 = tok1->tokAt(3)->link()->next()->link(); - } - - tok = tok->next()->link()->next(); - } - } - } -} - -void CheckOther::duplicateIfError(const Token *tok1, const Token *tok2) -{ - std::list toks; - toks.push_back(tok2); - toks.push_back(tok1); - - reportError(toks, Severity::style, "duplicateIf", "Found duplicate if expressions.\n" - "Finding the same expression more than once is suspicious and might indicate " - "a cut and paste or logic error. Please examine this code carefully to determine " - "if it is correct."); -} - -//----------------------------------------------------------------------------- -// check for duplicate code in if and else branches -// if (a) { b = true; } else { b = true; } -//----------------------------------------------------------------------------- - -void CheckOther::checkDuplicateBranch() -{ - if (!_settings->isEnabled("style")) - return; - - if (!_settings->inconclusive) - return; - - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - - std::list::const_iterator scope; - - for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - // only check functions - if (scope->type != Scope::eFunction) - continue; - - // check all the code in the function for if (..) else - for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) { - if (Token::simpleMatch(tok, "if (") && tok->strAt(-1) != "else" && - Token::simpleMatch(tok->next()->link(), ") {") && - Token::simpleMatch(tok->next()->link()->next()->link(), "} else {")) { - // save if branch code - std::string branch1 = stringifyTokens(tok->next()->link()->tokAt(2), tok->next()->link()->next()->link()->previous()); - - // find else branch - const Token *tok1 = tok->next()->link()->next()->link(); - - // save else branch code - std::string branch2 = stringifyTokens(tok1->tokAt(3), tok1->tokAt(2)->link()->previous()); - - // check for duplicates - if (branch1 == branch2) - duplicateBranchError(tok, tok1->tokAt(2)); - - tok = tok->next()->link()->next(); - } - } - } -} - -void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2) -{ - std::list toks; - toks.push_back(tok2); - toks.push_back(tok1); - - reportError(toks, Severity::style, "duplicateBranch", "Found duplicate branches for if and else.\n" - "Finding the same code for an if branch and an else branch is suspicious and " - "might indicate a cut and paste or logic error. Please examine this code " - "carefully to determine if it is correct."); -} - -//--------------------------------------------------------------------------- -// check for the same expression on both sides of an operator -// (x == x), (x && x), (x || x) -// (x.y == x.y), (x.y && x.y), (x.y || x.y) -//--------------------------------------------------------------------------- - -void CheckOther::checkDuplicateExpression() -{ - if (!_settings->isEnabled("style")) - return; - - // Parse all executing scopes.. - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - - std::list::const_iterator scope; - - for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - // only check functions - if (scope->type != Scope::eFunction) - continue; - - for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) { - if (Token::Match(tok, "(|&&|%oror% %var% &&|%oror%|==|!=|<=|>=|<|>|-|%or% %var% )|&&|%oror%") && - tok->strAt(1) == tok->strAt(3)) { - // float == float and float != float are valid NaN checks - if (Token::Match(tok->tokAt(2), "==|!=") && tok->next()->varId()) { - const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId()); - if (var && var->typeStartToken() == var->typeEndToken()) { - if (Token::Match(var->typeStartToken(), "float|double")) - continue; - } - } - - duplicateExpressionError(tok->next(), tok->tokAt(3), tok->strAt(2)); - } else if (Token::Match(tok, "(|&&|%oror% %var% . %var% &&|%oror%|==|!=|<=|>=|<|>|-|%or% %var% . %var% )|&&|%oror%") && - tok->strAt(1) == tok->strAt(5) && tok->strAt(3) == tok->strAt(7)) { - duplicateExpressionError(tok->next(), tok->tokAt(6), tok->strAt(4)); - } - } - } -} - -void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op) -{ - std::list toks; - toks.push_back(tok2); - toks.push_back(tok1); - - reportError(toks, Severity::style, "duplicateExpression", "Same expression on both sides of \'" + op + "\'.\n" - "Finding the same expression on both sides of an operator is suspicious and might " - "indicate a cut and paste or logic error. Please examine this code carefully to " - "determine if it is correct."); -} - - -//--------------------------------------------------------------------------- -// Check for string comparison involving two static strings. -// if(strcmp("00FF00","00FF00")==0) // <- statement is always true -//--------------------------------------------------------------------------- - -void CheckOther::checkAlwaysTrueOrFalseStringCompare() -{ - if (!_settings->isEnabled("style")) - return; - - const char pattern1[] = "strcmp|stricmp|strcmpi|strcasecmp|wcscmp ( %str% , %str% )"; - const char pattern2[] = "QString :: compare ( %str% , %str% )"; - - const Token *tok = _tokenizer->tokens(); - while (tok && (tok = Token::findmatch(tok, pattern1)) != NULL) { - alwaysTrueFalseStringCompare(tok, tok->strAt(2), tok->strAt(4)); - tok = tok->tokAt(5); - } - - tok = _tokenizer->tokens(); - while (tok && (tok = Token::findmatch(tok, pattern2)) != NULL) { - alwaysTrueFalseStringCompare(tok, tok->strAt(4), tok->strAt(6)); - tok = tok->tokAt(7); - } -} - -void CheckOther::alwaysTrueFalseStringCompare(const Token *tok, const std::string& str1, const std::string& str2) -{ - const size_t stringLen = 10; - const std::string string1 = (str1.size() < stringLen) ? str1 : (str1.substr(0, stringLen-2) + ".."); - const std::string string2 = (str2.size() < stringLen) ? str2 : (str2.substr(0, stringLen-2) + ".."); - - if (str1 == str2) { - reportError(tok, Severity::warning, "staticStringCompare", - "Comparison of always identical static strings.\n" - "The compared strings, '" + string1 + "' and '" + string2 + "', are always identical. " - "If the purpose is to compare these two strings, the comparison is unnecessary. " - "If the strings are supposed to be different, then there is a bug somewhere."); - } else { - reportError(tok, Severity::performance, "staticStringCompare", - "Unnecessary comparison of static strings.\n" - "The compared strings, '" + string1 + "' and '" + string2 + "', are static and always different. " - "If the purpose is to compare these two strings, the comparison is unnecessary."); - } -} - -//----------------------------------------------------------------------------- - -void CheckOther::cstyleCastError(const Token *tok) -{ - reportError(tok, Severity::style, "cstyleCast", "C-style pointer casting"); -} - -void CheckOther::dangerousUsageStrtolError(const Token *tok) -{ - reportError(tok, Severity::error, "dangerousUsageStrtol", "Invalid radix in call to strtol or strtoul. Must be 0 or 2-36"); -} - -void CheckOther::sprintfOverlappingDataError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::error, "sprintfOverlappingData", - "Undefined behavior: variable is used as parameter and destination in s[n]printf().\n" - "The variable '" + varname + "' is used both as a parameter and as a destination in " - "s[n]printf(). The origin and destination buffers overlap. Quote from glibc (C-library) " - "documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): " - "'If copying takes place between objects that overlap as a result of a call " - "to sprintf() or snprintf(), the results are undefined.'"); -} - -void CheckOther::udivError(const Token *tok) -{ - reportError(tok, Severity::error, "udivError", "Unsigned division. The result will be wrong."); -} - -void CheckOther::unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname) -{ - reportError(tok, Severity::style, "unusedStructMember", "struct or union member '" + structname + "::" + varname + "' is never used"); -} - -void CheckOther::passedByValueError(const Token *tok, const std::string &parname) -{ - reportError(tok, Severity::performance, "passedByValue", - "Function parameter '" + parname + "' should be passed by reference.\n" - "Parameter '" + parname + "' is passed as a value. It could be passed " - "as a (const) reference which is usually faster and recommended in C++."); -} - -void CheckOther::constStatementError(const Token *tok, const std::string &type) -{ - reportError(tok, Severity::warning, "constStatement", "Redundant code: Found a statement that begins with " + type + " constant"); -} - -void CheckOther::charArrayIndexError(const Token *tok) -{ - reportError(tok, - Severity::warning, - "charArrayIndex", - "Using char type as array index\n" - "Using signed char type as array index. If the value " - "can be greater than 127 there will be a buffer overflow " - "(because of sign extension)."); -} - -void CheckOther::charBitOpError(const Token *tok) -{ - reportError(tok, - Severity::warning, - "charBitOp", - "When using char variables in bit operations, sign extension can generate unexpected results.\n" - "When using char variables in bit operations, sign extension can generate unexpected results. For example:\n" - " char c = 0x80;\n" - " int i = 0 | c;\n" - " if (i & 0x8000)\n" - " printf(\"not expected\");\n" - "The 'not expected' will be printed on the screen."); -} - -void CheckOther::variableScopeError(const Token *tok, const std::string &varname) -{ - reportError(tok, - Severity::information, - "variableScope", - "The scope of the variable '" + varname + "' can be reduced\n" - "The scope of the variable '" + varname + "' can be reduced. Warning: It can be unsafe " - "to fix this message. Be careful. Especially when there are inner loops. Here is an " - "example where cppcheck will write that the scope for 'i' can be reduced:\n" - "void f(int x)\n" - "{\n" - " int i = 0;\n" - " if (x) {\n" - " // it's safe to move 'int i = 0' here\n" - " for (int n = 0; n < 10; ++n) {\n" - " // it is possible but not safe to move 'int i = 0' here\n" - " do_something(&i);\n" - " }\n" - " }\n" - "}\n" - "When you see this message it is always safe to reduce the variable scope 1 level."); -} - -void CheckOther::conditionAlwaysTrueFalse(const Token *tok, const std::string &truefalse) -{ - reportError(tok, Severity::style, "conditionAlwaysTrueFalse", "Condition is always " + truefalse); -} - -void CheckOther::strPlusChar(const Token *tok) -{ - reportError(tok, Severity::error, "strPlusChar", "Unusual pointer arithmetic"); -} - -void CheckOther::zerodivError(const Token *tok) -{ - reportError(tok, Severity::error, "zerodiv", "Division by zero"); -} - -void CheckOther::mathfunctionCallError(const Token *tok, const unsigned int numParam) -{ - if (tok) { - if (numParam == 1) - reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->tokAt(2)->str() + " to " + tok->str() + "() leads to undefined result"); - else if (numParam == 2) - reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->tokAt(2)->str() + " and " + tok->tokAt(4)->str() + " to " + tok->str() + "() leads to undefined result"); - } else - reportError(tok, Severity::error, "wrongmathcall", "Passing value " " to " "() leads to undefined result"); -} - -void CheckOther::fflushOnInputStreamError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::error, - "fflushOnInputStream", "fflush() called on input stream \"" + varname + "\" may result in undefined behaviour"); -} - -void CheckOther::sizeofsizeof() -{ - if (!_settings->isEnabled("style")) - return; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "sizeof (| sizeof")) { - sizeofsizeofError(tok); - tok = tok->next(); - } - } -} - -void CheckOther::sizeofsizeofError(const Token *tok) -{ - reportError(tok, Severity::warning, - "sizeofsizeof", "Calling sizeof for 'sizeof'.\n" - "Calling sizeof for 'sizeof looks like a suspicious code and " - "most likely there should be just one 'sizeof'. The current " - "code is equivalent to 'sizeof(size_t)'"); -} - -void CheckOther::sizeofCalculation() -{ - if (!_settings->isEnabled("style")) - return; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "sizeof (")) { - unsigned int parlevel = 0; - for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) { - if (tok2->str() == "(") - ++parlevel; - else if (tok2->str() == ")") { - if (parlevel <= 1) - break; - --parlevel; - } else if (Token::Match(tok2, "+|/")) { - sizeofCalculationError(tok2); - break; - } - } - } - } -} - -void CheckOther::sizeofCalculationError(const Token *tok) -{ - reportError(tok, Severity::warning, - "sizeofCalculation", "Found calculation inside sizeof()"); -} - -void CheckOther::redundantAssignmentInSwitchError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::warning, - "redundantAssignInSwitch", "Redundant assignment of \"" + varname + "\" in switch"); -} - -void CheckOther::switchCaseFallThrough(const Token *tok) -{ - reportError(tok, Severity::style, - "switchCaseFallThrough", "Switch falls through case without comment"); -} - -void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::warning, - "selfAssignment", "Redundant assignment of \"" + varname + "\" to itself"); -} - -void CheckOther::assignmentInAssertError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::warning, - "assignmentInAssert", "Assert statement modifies '" + varname + "'.\n" - "Variable '" + varname + "' is modified inside assert statement. " - "Assert statements are removed from release builds so the code inside " - "assert statement is not run. If the code is needed also in release " - "builds this is a bug."); -} - -void CheckOther::incorrectLogicOperatorError(const Token *tok, bool always) -{ - if (always) - reportError(tok, Severity::warning, - "incorrectLogicOperator", "Mutual exclusion over || always evaluates to true. Did you intend to use && instead?"); - else - reportError(tok, Severity::warning, - "incorrectLogicOperator", "Expression always evaluates to false. Did you intend to use || instead?"); -} - -void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname) -{ - reportError(tok, Severity::error, - "unusedScopedObject", "instance of \"" + varname + "\" object destroyed immediately"); -} - -void CheckOther::catchExceptionByValueError(const Token *tok) -{ - reportError(tok, Severity::style, - "catchExceptionByValue", "Exception should be caught by reference.\n" - "The exception is caught as a value. It could be caught " - "as a (const) reference which is usually recommended in C++."); -} - -void CheckOther::memsetZeroBytesError(const Token *tok, const std::string &varname) -{ - const std::string summary("memset() called to fill 0 bytes of \'" + varname + "\'"); - const std::string verbose(summary + ". Second and third arguments might be inverted."); - reportError(tok, Severity::warning, "memsetZeroBytes", summary + "\n" + verbose); -} - -void CheckOther::incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string, const std::string &len) -{ - reportError(tok, Severity::warning, "incorrectStringCompare", "String literal " + string + " doesn't match length argument for " + func + "(" + len + ")."); -} - -void CheckOther::comparisonOfBoolWithIntError(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::warning, "comparisonOfBoolWithInt", - "Comparison of a boolean with a non-zero integer\n" - "The expression \"!" + varname + "\" is of type 'bool' but is compared against a non-zero 'int'."); -} - -void CheckOther::duplicateBreakError(const Token *tok) -{ - reportError(tok, Severity::style, "duplicateBreak", - "Consecutive break or continue statements are unnecessary\n" - "The second of the two statements can never be executed, and so should be removed\n"); -} - - -void CheckOther::checkAssignBoolToPointer() -{ - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (Token::Match(tok, "[;{}] %var% = %bool% ;")) { - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - - const Variable *var1(symbolDatabase->getVariableFromVarId(tok->next()->varId())); - - // Is variable a pointer? - if (var1 && var1->nameToken()->strAt(-1) == "*") - assignBoolToPointerError(tok->next()); - } - } -} - -void CheckOther::assignBoolToPointerError(const Token *tok) -{ - reportError(tok, Severity::error, "assignBoolToPointer", - "Assigning bool value to pointer (converting bool value to address)"); -} - -//--------------------------------------------------------------------------- -// Check testing sign of unsigned variables. -//--------------------------------------------------------------------------- - -void CheckOther::checkSignOfUnsignedVariable() -{ - if (!_settings->isEnabled("style")) - return; - - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - - std::list::const_iterator scope; - - for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - // only check functions - if (scope->type != Scope::eFunction) - continue; - - // check all the code in the function - for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) { - if (Token::Match(tok, "( %var% <|<= 0 )") && tok->next()->varId()) { - const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId()); - if (var && var->typeEndToken()->isUnsigned()) - unsignedLessThanZero(tok->next(), tok->next()->str()); - } else if (Token::Match(tok, "( 0 > %var% )") && tok->tokAt(3)->varId()) { - const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId()); - if (var && var->typeEndToken()->isUnsigned()) - unsignedLessThanZero(tok->tokAt(3), tok->strAt(3)); - } else if (Token::Match(tok, "( 0 <= %var% )") && tok->tokAt(3)->varId()) { - const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId()); - if (var && var->typeEndToken()->isUnsigned()) - unsignedPositive(tok->tokAt(3), tok->strAt(3)); - } - } - } -} - -void CheckOther::unsignedLessThanZero(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::style, "unsignedLessThanZero", - "Checking if unsigned variable '" + varname + "' is less than zero.\n" - "An unsigned variable will never be negative so it is either pointless or " - "an error to check if it is."); -} - -void CheckOther::unsignedPositive(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::style, "unsignedPositive", - "Checking if unsigned variable '" + varname + "' is positive is always true.\n" - "An unsigned variable can't be negative so it is either pointless or " - "an error to check if it is."); -} diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 2cf7b9037..3d9f15701 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -330,21 +330,6 @@ bool CheckAutoVariables::checkAutoVariableAssignment(const Token *expr, bool inc //--------------------------------------------------------------------------- -void CheckAutoVariables::errorReturnAddressToAutoVariable(const Token *tok) -{ - reportError(tok, Severity::error, "returnAddressOfAutoVariable", "Address of an auto-variable returned.", CWE562, Certainty::normal); -} - -void CheckAutoVariables::errorReturnAddressToAutoVariable(const Token *tok, const ValueFlow::Value *value) -{ - reportError(tok, Severity::error, "returnAddressOfAutoVariable", "Address of auto-variable '" + value->tokvalue->astOperand1()->expressionString() + "' returned", CWE562, Certainty::normal); -} - -void CheckAutoVariables::errorReturnPointerToLocalArray(const Token *tok) -{ - reportError(tok, Severity::error, "returnLocalVariable", "Pointer to local array variable returned.", CWE562, Certainty::normal); -} - void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inconclusive) { if (!inconclusive) { @@ -366,16 +351,6 @@ void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inco } } -void CheckAutoVariables::errorReturnAddressOfFunctionParameter(const Token *tok, const std::string &varname) -{ - reportError(tok, Severity::error, "returnAddressOfFunctionParameter", - "$symbol:" + varname + "\n" - "Address of function parameter '$symbol' returned.\n" - "Address of the function parameter '$symbol' becomes invalid after the function exits because " - "function parameters are stored on the stack which is freed when the function exits. Thus the returned " - "value is invalid.", CWE562, Certainty::normal); -} - void CheckAutoVariables::errorUselessAssignmentArg(const Token *tok) { reportError(tok, diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h index 7b58db07a..23cf50265 100644 --- a/lib/checkautovariables.h +++ b/lib/checkautovariables.h @@ -77,9 +77,6 @@ public: void checkVarLifetimeScope(const Token * start, const Token * end); private: - void errorReturnAddressToAutoVariable(const Token *tok); - void errorReturnAddressToAutoVariable(const Token *tok, const ValueFlow::Value *value); - void errorReturnPointerToLocalArray(const Token *tok); void errorAutoVariableAssignment(const Token *tok, bool inconclusive); void errorReturnDanglingLifetime(const Token *tok, const ValueFlow::Value* val); void errorInvalidLifetime(const Token *tok, const ValueFlow::Value* val); @@ -90,7 +87,6 @@ private: void errorDanglingTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive); void errorReturnTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive); void errorInvalidDeallocation(const Token *tok, const ValueFlow::Value *val); - void errorReturnAddressOfFunctionParameter(const Token *tok, const std::string &varname); void errorUselessAssignmentArg(const Token *tok); void errorUselessAssignmentPtrArg(const Token *tok); @@ -98,14 +94,11 @@ private: ErrorPath errorPath; CheckAutoVariables c(nullptr,settings,errorLogger); c.errorAutoVariableAssignment(nullptr, false); - c.errorReturnAddressToAutoVariable(nullptr); - c.errorReturnPointerToLocalArray(nullptr); c.errorReturnReference(nullptr, errorPath, false); c.errorDanglingReference(nullptr, nullptr, errorPath); c.errorReturnTempReference(nullptr, errorPath, false); c.errorDanglingTempReference(nullptr, errorPath, false); c.errorInvalidDeallocation(nullptr, nullptr); - c.errorReturnAddressOfFunctionParameter(nullptr, "parameter"); c.errorUselessAssignmentArg(nullptr); c.errorUselessAssignmentPtrArg(nullptr); c.errorReturnDanglingLifetime(nullptr, nullptr); diff --git a/lib/checkbool.h b/lib/checkbool.h index 9b843a5cd..efaa5a59f 100644 --- a/lib/checkbool.h +++ b/lib/checkbool.h @@ -111,7 +111,6 @@ private: void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override { CheckBool c(nullptr, settings, errorLogger); - c.assignBoolToPointerError(nullptr); c.assignBoolToFloatError(nullptr); c.comparisonOfFuncReturningBoolError(nullptr, "func_name"); diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 9e2c68468..3d6a1b297 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -56,7 +56,6 @@ static const CWE CWE131(131U); // Incorrect Calculation of Buffer Size static const CWE CWE170(170U); // Improper Null Termination static const CWE CWE_ARGUMENT_SIZE(398U); // Indicator of Poor Code Quality static const CWE CWE_ARRAY_INDEX_THEN_CHECK(398U); // Indicator of Poor Code Quality -static const CWE CWE682(682U); // Incorrect Calculation static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior static const CWE CWE_POINTER_ARITHMETIC_OVERFLOW(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior static const CWE CWE_BUFFER_UNDERRUN(786U); // Access of Memory Location Before Start of Buffer diff --git a/lib/checkio.h b/lib/checkio.h index e660f9832..7e330c332 100644 --- a/lib/checkio.h +++ b/lib/checkio.h @@ -134,7 +134,6 @@ private: void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override { CheckIO c(nullptr, settings, errorLogger); - c.coutCerrMisusageError(nullptr, "cout"); c.fflushOnInputStreamError(nullptr, "stdin"); c.ioWithoutPositioningError(nullptr); diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 64f93d31f..9f6a2f729 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -338,21 +338,11 @@ void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &var reportErr(tok, Severity::error, "resourceLeak", errmsg, CWE(775U)); } -void CheckMemoryLeak::deallocDeallocError(const Token *tok, const std::string &varname) const -{ - reportErr(tok, Severity::error, "deallocDealloc", "$symbol:" + varname + "\nDeallocating a deallocated pointer: $symbol", CWE(415U)); -} - void CheckMemoryLeak::deallocuseError(const Token *tok, const std::string &varname) const { reportErr(tok, Severity::error, "deallocuse", "$symbol:" + varname + "\nDereferencing '$symbol' after it is deallocated / released", CWE(416U)); } -void CheckMemoryLeak::mismatchSizeError(const Token *tok, const std::string &sz) const -{ - reportErr(tok, Severity::error, "mismatchSize", "The allocated size " + sz + " is not a multiple of the underlying type's size.", CWE(131U)); -} - void CheckMemoryLeak::mismatchAllocDealloc(const std::list &callstack, const std::string &varname) const { reportErr(callstack, Severity::error, "mismatchAllocDealloc", "$symbol:" + varname + "\nMismatching allocation and deallocation: $symbol", CWE(762U)); diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index 5eae5509d..cf6712a23 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -137,14 +137,7 @@ public: */ void resourceLeakError(const Token *tok, const std::string &varname) const; - /** - * @brief Report error: deallocating a deallocated pointer - * @param tok token where error occurs - * @param varname name of variable - */ - void deallocDeallocError(const Token *tok, const std::string &varname) const; void deallocuseError(const Token *tok, const std::string &varname) const; - void mismatchSizeError(const Token *tok, const std::string &sz) const; void mismatchAllocDealloc(const std::list &callstack, const std::string &varname) const; void memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const; @@ -196,13 +189,9 @@ private: /** Report all possible errors (for the --errorlist) */ void getErrorMessages(ErrorLogger *e, const Settings *settings) const override { CheckMemoryLeakInFunction c(nullptr, settings, e); - c.memleakError(nullptr, "varname"); c.resourceLeakError(nullptr, "varname"); - - c.deallocDeallocError(nullptr, "varname"); c.deallocuseError(nullptr, "varname"); - c.mismatchSizeError(nullptr, "sz"); const std::list callstack; c.mismatchAllocDealloc(callstack, "varname"); c.memleakUponReallocFailureError(nullptr, "realloc", "varname"); @@ -352,7 +341,6 @@ private: void getErrorMessages(ErrorLogger *e, const Settings *settings) const override { CheckMemoryLeakNoVar c(nullptr, settings, e); - c.functionCallLeak(nullptr, "funcName", "funcName"); c.returnValueNotUsedError(nullptr, "funcName"); c.unsafeArgAllocError(nullptr, "funcName", "shared_ptr", "int"); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 6485ee4cc..3380aa770 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -59,7 +59,6 @@ static const struct CWE CWE362(362U); // Concurrent Execution using Shared Res static const struct CWE CWE369(369U); // Divide By Zero static const struct CWE CWE398(398U); // Indicator of Poor Code Quality static const struct CWE CWE475(475U); // Undefined Behavior for Input to API -static const struct CWE CWE482(482U); // Comparing instead of Assigning static const struct CWE CWE561(561U); // Dead Code static const struct CWE CWE563(563U); // Assignment to Variable without Use ('Unused Variable') static const struct CWE CWE570(570U); // Expression is Always False @@ -511,14 +510,6 @@ void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const "Buffer '$symbol' is being written before its old content has been used.", CWE563, Certainty::normal); } -void CheckOther::redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var) -{ - const std::list callstack = { tok1, tok2 }; - reportError(callstack, Severity::style, "redundantCopyInSwitch", - "$symbol:" + var + "\n" - "Buffer '$symbol' is being written before its old content has been used. 'break;' missing?", CWE563, Certainty::normal); -} - void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive) { const ErrorPath errorPath = { ErrorPathItem(tok1, var + " is assigned"), ErrorPathItem(tok2, var + " is overwritten") }; diff --git a/lib/checkother.h b/lib/checkother.h index 84073ae72..4c3bf2fa1 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -247,7 +247,6 @@ private: void redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive); void redundantAssignmentInSwitchError(const Token *tok1, const Token *tok2, const std::string &var); void redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var); - void redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var); void redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname); void suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString); void selfAssignmentError(const Token *tok, const std::string &varname); @@ -315,7 +314,6 @@ private: c.charBitOpError(nullptr); c.variableScopeError(nullptr, "varname"); c.redundantAssignmentInSwitchError(nullptr, nullptr, "var"); - c.redundantCopyInSwitchError(nullptr, nullptr, "var"); c.suspiciousCaseInSwitchError(nullptr, "||"); c.selfAssignmentError(nullptr, "varname"); c.clarifyCalculationError(nullptr, "+"); diff --git a/lib/checksizeof.h b/lib/checksizeof.h index 208ca7d6a..a4e4516a4 100644 --- a/lib/checksizeof.h +++ b/lib/checksizeof.h @@ -103,7 +103,6 @@ private: void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override { CheckSizeof c(nullptr, settings, errorLogger); - c.sizeofForArrayParameterError(nullptr); c.sizeofForPointerError(nullptr, "varname"); c.divideBySizeofError(nullptr, "memset"); diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 9905686f2..f8f54aa6b 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -2495,21 +2495,6 @@ void CheckStl::dereferenceInvalidIteratorError(const Token* deref, const std::st "Possible dereference of an invalid iterator: $symbol. Make sure to check that the iterator is valid before dereferencing it - not after.", CWE825, Certainty::normal); } -void CheckStl::readingEmptyStlContainerError(const Token *tok, const ValueFlow::Value *value) -{ - const std::string varname = tok ? tok->str() : std::string("var"); - - std::string errmsg; - if (value && value->condition) - errmsg = "Reading from container '$symbol'. " + ValueFlow::eitherTheConditionIsRedundant(value->condition) + " or '$symbol' can be empty."; - else - errmsg = "Reading from empty STL container '$symbol'"; - - const ErrorPath errorPath = getErrorPath(tok, value, "Reading from empty container"); - - reportError(errorPath, value ? (value->errorSeverity() ? Severity::error : Severity::warning) : Severity::style, "reademptycontainer", "$symbol:" + varname +"\n" + errmsg, CWE398, !value ? Certainty::inconclusive : Certainty::normal); -} - void CheckStl::useStlAlgorithmError(const Token *tok, const std::string &algoName) { reportError(tok, Severity::style, "useStlAlgorithm", diff --git a/lib/checkstl.h b/lib/checkstl.h index 895082514..23225893b 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -230,8 +230,6 @@ private: void dereferenceInvalidIteratorError(const Token* deref, const std::string& iterName); void dereferenceInvalidIteratorError(const Token* tok, const ValueFlow::Value *value, bool inconclusive); - void readingEmptyStlContainerError(const Token* tok, const ValueFlow::Value *value=nullptr); - void useStlAlgorithmError(const Token *tok, const std::string &algoName); void knownEmptyContainerError(const Token *tok, const std::string& algo); @@ -273,7 +271,6 @@ private: c.uselessCallsEmptyError(nullptr); c.uselessCallsRemoveError(nullptr, "remove"); c.dereferenceInvalidIteratorError(nullptr, "i"); - c.readingEmptyStlContainerError(nullptr); c.useStlAlgorithmError(nullptr, emptyString); c.knownEmptyContainerError(nullptr, emptyString); c.globalLockGuardError(nullptr); diff --git a/lib/checkstring.h b/lib/checkstring.h index 446f7aa4d..64fa45822 100644 --- a/lib/checkstring.h +++ b/lib/checkstring.h @@ -96,7 +96,6 @@ private: void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override { CheckString c(nullptr, settings, errorLogger); - c.stringLiteralWriteError(nullptr, nullptr); c.sprintfOverlappingDataError(nullptr, nullptr, "varname"); c.strPlusCharError(nullptr); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 402746c10..b8e71426f 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -51,7 +51,6 @@ namespace tinyxml2 { // CWE ids used: static const struct CWE CWE_USE_OF_UNINITIALIZED_VARIABLE(457U); -static const struct CWE CWE_USE_OF_POTENTIALLY_DANGEROUS_FUNCTION(676U); // Register this check class (by creating a static instance of it) namespace { @@ -1497,11 +1496,6 @@ bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, All return false; } -void CheckUninitVar::uninitstringError(const Token *tok, const std::string &varname, bool strncpy_) -{ - reportError(tok, Severity::error, "uninitstring", "$symbol:" + varname + "\nDangerous usage of '$symbol'" + (strncpy_ ? " (strncpy doesn't always null-terminate it)." : " (not null-terminated)."), CWE_USE_OF_POTENTIALLY_DANGEROUS_FUNCTION, Certainty::normal); -} - void CheckUninitVar::uninitdataError(const Token *tok, const std::string &varname) { reportError(tok, Severity::error, "uninitdata", "$symbol:" + varname + "\nMemory is allocated but not initialized: $symbol", CWE_USE_OF_UNINITIALIZED_VARIABLE, Certainty::normal); diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index efa93a4a1..ce3344682 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -116,7 +116,6 @@ public: bool analyseWholeProgram(const CTU::FileInfo *ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; void uninitvarError(const Token* tok, const ValueFlow::Value& v); - void uninitstringError(const Token *tok, const std::string &varname, bool strncpy_); void uninitdataError(const Token *tok, const std::string &varname); void uninitvarError(const Token *tok, const std::string &varname, ErrorPath errorPath); void uninitvarError(const Token *tok, const std::string &varname) { @@ -142,9 +141,7 @@ private: ValueFlow::Value v{}; - // error c.uninitvarError(nullptr, v); - c.uninitstringError(nullptr, "varname", true); c.uninitdataError(nullptr, "varname"); c.uninitStructMemberError(nullptr, "a.b"); } diff --git a/lib/checkunusedvar.h b/lib/checkunusedvar.h index 0547c5562..4a7655f26 100644 --- a/lib/checkunusedvar.h +++ b/lib/checkunusedvar.h @@ -85,8 +85,6 @@ private: void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override { CheckUnusedVar c(nullptr, settings, errorLogger); - - // style/warning c.unusedVariableError(nullptr, "varname"); c.allocatedButUnusedVariableError(nullptr, "varname"); c.unreadVariableError(nullptr, "varname", false);