From 42fcb04d0c77290eeeb03e434b35a08b91d332b4 Mon Sep 17 00:00:00 2001 From: PKEuS Date: Wed, 10 Apr 2013 09:25:50 -0700 Subject: [PATCH] Moved checks related to boolean type (not condition checking!) from checkother into new file --- lib/checkbool.cpp | 417 +++++++++++++++++ lib/checkbool.h | 134 ++++++ lib/checkother.cpp | 387 +--------------- lib/checkother.h | 51 --- lib/cppcheck.vcxproj | 2 + lib/cppcheck.vcxproj.filters | 6 + test/testbool.cpp | 768 ++++++++++++++++++++++++++++++++ test/testother.cpp | 707 ----------------------------- test/testrunner.vcxproj | 1 + test/testrunner.vcxproj.filters | 3 + 10 files changed, 1332 insertions(+), 1144 deletions(-) create mode 100644 lib/checkbool.cpp create mode 100644 lib/checkbool.h create mode 100644 test/testbool.cpp diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp new file mode 100644 index 000000000..33aef2a83 --- /dev/null +++ b/lib/checkbool.cpp @@ -0,0 +1,417 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2013 Daniel Marjamäki and 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 . + */ + + +//--------------------------------------------------------------------------- +#include "checkbool.h" +#include "mathlib.h" +#include "symboldatabase.h" +//--------------------------------------------------------------------------- + +// Register this check class (by creating a static instance of it) +namespace { + CheckBool instance; +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +void CheckBool::checkIncrementBoolean() +{ + if (!_settings->isEnabled("style")) + return; + + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { + if (Token::Match(tok, "%var% ++")) { + if (tok->varId()) { + const Variable *var = tok->variable(); + + if (var && var->typeEndToken()->str() == "bool") + incrementBooleanError(tok); + } + } + } + } +} + +void CheckBool::incrementBooleanError(const Token *tok) +{ + reportError( + tok, + Severity::style, + "incrementboolean", + "Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\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. You should assign it the value 'true' instead." + ); +} + +//--------------------------------------------------------------------------- +// if (bool & bool) -> if (bool && bool) +// if (bool | bool) -> if (bool || bool) +//--------------------------------------------------------------------------- +void CheckBool::checkBitwiseOnBoolean() +{ + if (!_settings->isEnabled("style")) + return; + + // danmar: this is inconclusive because I don't like that there are + // warnings for calculations. Example: set_flag(a & b); + if (!_settings->inconclusive) + return; + + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { + if (Token::Match(tok, "(|.|return|&&|%oror%|throw|, %var% [&|]")) { + const Variable *var = tok->next()->variable(); + if (var && var->typeEndToken()->str() == "bool") { + bitwiseOnBooleanError(tok->next(), var->name(), tok->strAt(2) == "&" ? "&&" : "||"); + tok = tok->tokAt(2); + } + } else if (Token::Match(tok, "[&|] %var% )|.|return|&&|%oror%|throw|,") && (!tok->previous() || !tok->previous()->isExtendedOp() || tok->strAt(-1) == ")" || tok->strAt(-1) == "]")) { + const Variable *var = tok->next()->variable(); + if (var && var->typeEndToken()->str() == "bool") { + bitwiseOnBooleanError(tok->next(), var->name(), tok->str() == "&" ? "&&" : "||"); + tok = tok->tokAt(2); + } + } + } + } +} + +void CheckBool::bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op) +{ + reportError(tok, Severity::style, "bitwiseOnBoolean", + "Boolean variable '" + varname + "' is used in bitwise operation. Did you mean '" + op + "'?", true); +} + +//--------------------------------------------------------------------------- +// if (!x==3) <- Probably meant to be "x!=3" +//--------------------------------------------------------------------------- + +static bool isBool(const Variable* var) +{ + return(var && var->typeEndToken()->str() == "bool"); +} +static bool isNonBoolStdType(const Variable* var) +{ + return(var && var->typeEndToken()->isStandardType() && var->typeEndToken()->str() != "bool"); +} +void CheckBool::checkComparisonOfBoolWithInt() +{ + if (!_settings->isEnabled("warning")) + return; + + const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { + if (tok->next() && tok->next()->type() == Token::eComparisonOp && (!tok->previous() || !tok->previous()->isArithmeticalOp()) && (!tok->tokAt(3) || !tok->tokAt(3)->isArithmeticalOp())) { + const Token* const right = tok->tokAt(2); + if ((tok->varId() && right->isNumber()) || (tok->isNumber() && right->varId())) { // Comparing variable with number + const Token* varTok = tok; + const Token* numTok = right; + if (tok->isNumber() && right->varId()) // num with var + std::swap(varTok, numTok); + if (isBool(varTok->variable()) && // Variable has to be a boolean + ((tok->strAt(1) != "==" && tok->strAt(1) != "!=") || + (MathLib::toLongNumber(numTok->str()) != 0 && MathLib::toLongNumber(numTok->str()) != 1))) { // == 0 and != 0 are allowed, for C also == 1 and != 1 + comparisonOfBoolWithIntError(varTok, numTok->str(), tok->strAt(1) == "==" || tok->strAt(1) == "!="); + } + } else if (tok->isBoolean() && right->varId()) { // Comparing boolean constant with variable + if (isNonBoolStdType(right->variable())) { // Variable has to be of non-boolean standard type + comparisonOfBoolWithIntError(right, tok->str(), false); + } else if (tok->strAt(1) != "==" && tok->strAt(1) != "!=") { + comparisonOfBoolWithInvalidComparator(right, tok->str()); + } + } else if (tok->varId() && right->isBoolean()) { // Comparing variable with boolean constant + if (isNonBoolStdType(tok->variable())) { // Variable has to be of non-boolean standard type + comparisonOfBoolWithIntError(tok, right->str(), false); + } else if (tok->strAt(1) != "==" && tok->strAt(1) != "!=") { + comparisonOfBoolWithInvalidComparator(right, tok->str()); + } + } else if (tok->isNumber() && right->isBoolean()) { // number constant with boolean constant + comparisonOfBoolWithIntError(tok, right->str(), false); + } else if (tok->isBoolean() && right->isNumber()) { // number constant with boolean constant + comparisonOfBoolWithIntError(tok, tok->str(), false); + } else if (tok->varId() && right->varId()) { // Comparing two variables, one of them boolean, one of them integer + const Variable* var1 = right->variable(); + const Variable* var2 = tok->variable(); + if (isBool(var1) && isNonBoolStdType(var2)) // Comparing boolean with non-bool standard type + comparisonOfBoolWithIntError(tok, var1->name(), false); + else if (isNonBoolStdType(var1) && isBool(var2)) // Comparing non-bool standard type with boolean + comparisonOfBoolWithIntError(tok, var2->name(), false); + } + } + } + } +} + +void CheckBool::comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1) +{ + if (n0o1) + reportError(tok, Severity::warning, "comparisonOfBoolWithInt", + "Comparison of a boolean with an integer that is neither 1 nor 0.\n" + "The expression '" + expression + "' is of type 'bool' " + "and it is compared against an integer value that is " + "neither 1 nor 0."); + else + reportError(tok, Severity::warning, "comparisonOfBoolWithInt", + "Comparison of a boolean with an integer.\n" + "The expression '" + expression + "' is of type 'bool' " + "and it is compared against an integer value."); +} + +void CheckBool::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression) +{ + reportError(tok, Severity::warning, "comparisonOfBoolWithInvalidComparator", + "Comparison of a boolean value using relational operator (<, >, <= or >=).\n" + "The result of the expression '" + expression + "' is of type 'bool'. " + "Comparing 'bool' value using relational (<, >, <= or >=)" + " operator could cause unexpected results."); +} + +//------------------------------------------------------------------------------- +// Comparing functions which are returning value of type bool +//------------------------------------------------------------------------------- + +void CheckBool::checkComparisonOfFuncReturningBool() +{ + if (!_settings->isEnabled("style")) + return; + + if (!_tokenizer->isCPP()) + return; + + const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase(); + + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { + if (tok->type() != Token::eComparisonOp || tok->str() == "==" || tok->str() == "!=") + continue; + const Token *first_token; + bool first_token_func_of_type_bool = false; + if (tok->strAt(-1) == ")") { + first_token = tok->previous()->link()->previous(); + } else { + first_token = tok->previous(); + } + if (Token::Match(first_token, "%var% (") && !Token::Match(first_token->previous(), "::|.")) { + const Function* func = first_token->function(); + if (func && func->tokenDef && func->tokenDef->strAt(-1) == "bool") { + first_token_func_of_type_bool = true; + } + } + + Token *second_token = tok->next(); + bool second_token_func_of_type_bool = false; + while (second_token->str()=="!") { + second_token = second_token->next(); + } + if (Token::Match(second_token, "%var% (") && !Token::Match(second_token->previous(), "::|.")) { + const Function* func = second_token->function(); + if (func && func->tokenDef && func->tokenDef->strAt(-1) == "bool") { + second_token_func_of_type_bool = true; + } + } + + if ((first_token_func_of_type_bool == true) && (second_token_func_of_type_bool == true)) { + comparisonOfTwoFuncsReturningBoolError(first_token->next(), first_token->str(), second_token->str()); + } else if (first_token_func_of_type_bool == true) { + comparisonOfFuncReturningBoolError(first_token->next(), first_token->str()); + } else if (second_token_func_of_type_bool == true) { + comparisonOfFuncReturningBoolError(second_token->previous(), second_token->str()); + } + } + } +} + +void CheckBool::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression) +{ + reportError(tok, Severity::style, "comparisonOfFuncReturningBoolError", + "Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n" + "The return type of function '" + expression + "' is 'bool' " + "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)" + " operator could cause unexpected results."); +} + +void CheckBool::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2) +{ + reportError(tok, Severity::style, "comparisonOfTwoFuncsReturningBoolError", + "Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n" + "The return type of function '" + expression1 + "' and function '" + expression2 + "' is 'bool' " + "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)" + " operator could cause unexpected results."); +} + +//------------------------------------------------------------------------------- +// Comparison of bool with bool +//------------------------------------------------------------------------------- + +void CheckBool::checkComparisonOfBoolWithBool() +{ + // FIXME: This checking is "experimental" because of the false positives + // when self checking lib/tokenize.cpp (#2617) + if (!_settings->experimental) + return; + + if (!_settings->isEnabled("style")) + return; + + if (!_tokenizer->isCPP()) + return; + + const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); + + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { + if (tok->type() != Token::eComparisonOp || tok->str() == "==" || tok->str() == "!=") + continue; + bool first_token_bool = false; + bool second_token_bool = false; + + const Token *first_token = tok->previous(); + if (first_token->varId()) { + if (isBool(first_token->variable())) { + first_token_bool = true; + } + } + const Token *second_token = tok->next(); + if (second_token->varId()) { + if (isBool(second_token->variable())) { + second_token_bool = true; + } + } + if ((first_token_bool == true) && (second_token_bool == true)) { + comparisonOfBoolWithBoolError(first_token->next(), first_token->str()); + } + } + } +} + +void CheckBool::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression) +{ + reportError(tok, Severity::style, "comparisonOfBoolWithBoolError", + "Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n" + "The variable '" + expression + "' is of type 'bool' " + "and comparing 'bool' value using relational (<, >, <= or >=)" + " operator could cause unexpected results."); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CheckBool::checkAssignBoolToPointer() +{ + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { + if (Token::Match(tok, "!!* %var% = %bool% ;")) { + const Variable *var1(tok->next()->variable()); + + // Is variable a pointer? + if (var1 && var1->isPointer()) + assignBoolToPointerError(tok->next()); + } + } + } +} + +void CheckBool::assignBoolToPointerError(const Token *tok) +{ + reportError(tok, Severity::error, "assignBoolToPointer", + "Boolean value assigned to pointer."); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CheckBool::checkComparisonOfBoolExpressionWithInt() +{ + if (!_settings->isEnabled("warning")) + return; + + const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase(); + + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { + // Skip template parameters + if (tok->str() == "<" && tok->link()) { + tok = tok->link(); + continue; + } + + const Token* numTok = 0; + const Token* opTok = 0; + char op = 0; + if (Token::Match(tok, "&&|%oror% %any% ) %comp% %any%")) { + numTok = tok->tokAt(4); + opTok = tok->tokAt(3); + if (Token::Match(opTok, "<|>")) + op = opTok->str()[0]; + } else if (Token::Match(tok, "%any% %comp% ( %any% &&|%oror%")) { + numTok = tok; + opTok = tok->next(); + if (Token::Match(opTok, "<|>")) + op = opTok->str()[0]=='>'?'<':'>'; + } + + else if (Token::Match(tok, "! %var% %comp% %any%")) { + numTok = tok->tokAt(3); + opTok = tok->tokAt(2); + if (Token::Match(opTok, "<|>")) + op = opTok->str()[0]; + } else if (Token::Match(tok, "%any% %comp% ! %var%")) { + numTok = tok; + opTok = tok->next(); + if (Token::Match(opTok, "<|>")) + op = opTok->str()[0]=='>'?'<':'>'; + } + + if (numTok && opTok) { + if (numTok->isNumber()) { + if (((numTok->str() != "0" && numTok->str() != "1") || !Token::Match(opTok, "!=|==")) && !((op == '<' && numTok->str() == "1") || (op == '>' && numTok->str() == "0"))) + comparisonOfBoolExpressionWithIntError(tok, true); + } else if (isNonBoolStdType(numTok->variable())) + comparisonOfBoolExpressionWithIntError(tok, false); + } + } + } +} + +void CheckBool::comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1) +{ + if (n0o1) + reportError(tok, Severity::warning, "compareBoolExpressionWithInt", + "Comparison of a boolean expression with an integer other than 0 or 1."); + else + reportError(tok, Severity::warning, "compareBoolExpressionWithInt", + "Comparison of a boolean expression with an integer."); +} diff --git a/lib/checkbool.h b/lib/checkbool.h new file mode 100644 index 000000000..af9171fc2 --- /dev/null +++ b/lib/checkbool.h @@ -0,0 +1,134 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2013 Daniel Marjamäki and 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 . + */ + + +//--------------------------------------------------------------------------- +#ifndef CheckBoolH +#define CheckBoolH +//--------------------------------------------------------------------------- + +#include "config.h" +#include "check.h" +#include "settings.h" + +class Token; +class Function; +class Variable; + +/// @addtogroup Checks +/// @{ + + +/** @brief checks dealing with suspicous usage of boolean type (not for evaluating conditions) */ + +class CPPCHECKLIB CheckBool : public Check { +public: + /** @brief This constructor is used when registering the CheckClass */ + CheckBool() : Check(myName()) + { } + + /** @brief This constructor is used when running checks. */ + CheckBool(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) + { } + + /** @brief Run checks against the normal token list */ + void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { + CheckBool checkBool(tokenizer, settings, errorLogger); + + // Checks + checkBool.checkComparisonOfBoolExpressionWithInt(); + checkBool.checkComparisonOfBoolWithInt(); + } + + /** @brief Run checks against the simplified token list */ + void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { + CheckBool checkBool(tokenizer, settings, errorLogger); + + // Checks + checkBool.checkComparisonOfFuncReturningBool(); + checkBool.checkComparisonOfBoolWithBool(); + checkBool.checkIncrementBoolean(); + checkBool.checkAssignBoolToPointer(); + checkBool.checkBitwiseOnBoolean(); + } + + /** @brief %Check for comparison of function returning bool*/ + void checkComparisonOfFuncReturningBool(); + + /** @brief %Check for comparison of variable of type bool*/ + void checkComparisonOfBoolWithBool(); + + /** @brief %Check for using postfix increment on bool */ + void checkIncrementBoolean(); + + /** @brief %Check for suspicious comparison of a bool and a non-zero (and non-one) value (e.g. "if (!x==4)") */ + void checkComparisonOfBoolWithInt(); + + /** @brief assigning bool to pointer */ + void checkAssignBoolToPointer(); + + /** @brief %Check for using bool in bitwise expression */ + void checkBitwiseOnBoolean(); + + /** @brief %Check for comparing a bool expression with an integer other than 0 or 1 */ + void checkComparisonOfBoolExpressionWithInt(); + +private: + // Error messages.. + void comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression); + void comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2); + void comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression); + void incrementBooleanError(const Token *tok); + void comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1); + void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression); + void assignBoolToPointerError(const Token *tok); + void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op); + void comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1); + + void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { + CheckBool c(0, settings, errorLogger); + + c.assignBoolToPointerError(0); + c.comparisonOfFuncReturningBoolError(0, "func_name"); + c.comparisonOfTwoFuncsReturningBoolError(0, "func_name1", "func_name2"); + c.comparisonOfBoolWithBoolError(0, "var_name"); + c.incrementBooleanError(0); + c.comparisonOfBoolWithIntError(0, "varname", true); + c.bitwiseOnBooleanError(0, "varname", "&&"); + c.comparisonOfBoolExpressionWithIntError(0, true); + } + + static std::string myName() { + return "Boolean"; + } + + std::string classInfo() const { + return "Boolean type checks\n" + + "* using increment on boolean\n" + "* comparison of a boolean with a non-zero integer\n" + "* comparison of a boolean expression with an integer other than 0 or 1\n" + "* comparison of a function returning boolean value using relational operator\n" + "* comparison of a boolean value with boolean value using relational operator\n" + "* using bool in bitwise expression\n"; + } +}; +/// @} +//--------------------------------------------------------------------------- +#endif diff --git a/lib/checkother.cpp b/lib/checkother.cpp index d378c1926..a862f9c9c 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -111,40 +111,6 @@ void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::str ); } -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- -void CheckOther::checkIncrementBoolean() -{ - if (!_settings->isEnabled("style")) - return; - - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { - if (Token::Match(tok, "%var% ++")) { - if (tok->varId()) { - const Variable *var = tok->variable(); - - if (var && var->typeEndToken()->str() == "bool") - incrementBooleanError(tok); - } - } - } - } -} - -void CheckOther::incrementBooleanError(const Token *tok) -{ - reportError( - tok, - Severity::style, - "incrementboolean", - "Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\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. You should assign it the value 'true' instead." - ); -} //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- @@ -373,47 +339,6 @@ void CheckOther::clarifyStatementError(const Token *tok) "Thus, the dereference is meaningless. Did you intend to write '(*A)++;'?"); } -//--------------------------------------------------------------------------- -// if (bool & bool) -> if (bool && bool) -// if (bool | bool) -> if (bool || bool) -//--------------------------------------------------------------------------- -void CheckOther::checkBitwiseOnBoolean() -{ - if (!_settings->isEnabled("style")) - return; - - // danmar: this is inconclusive because I don't like that there are - // warnings for calculations. Example: set_flag(a & b); - if (!_settings->inconclusive) - return; - - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { - if (Token::Match(tok, "(|.|return|&&|%oror%|throw|, %var% [&|]")) { - const Variable *var = tok->next()->variable(); - if (var && var->typeEndToken()->str() == "bool") { - bitwiseOnBooleanError(tok->next(), var->name(), tok->strAt(2) == "&" ? "&&" : "||"); - tok = tok->tokAt(2); - } - } else if (Token::Match(tok, "[&|] %var% )|.|return|&&|%oror%|throw|,") && (!tok->previous() || !tok->previous()->isExtendedOp() || tok->strAt(-1) == ")" || tok->strAt(-1) == "]")) { - const Variable *var = tok->next()->variable(); - if (var && var->typeEndToken()->str() == "bool") { - bitwiseOnBooleanError(tok->next(), var->name(), tok->str() == "&" ? "&&" : "||"); - tok = tok->tokAt(2); - } - } - } - } -} - -void CheckOther::bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op) -{ - reportError(tok, Severity::style, "bitwiseOnBoolean", - "Boolean variable '" + varname + "' is used in bitwise operation. Did you mean '" + op + "'?", true); -} void CheckOther::checkSuspiciousSemicolon() { @@ -1805,93 +1730,6 @@ void CheckOther::sprintfOverlappingDataError(const Token *tok, const std::string "to sprintf() or snprintf(), the results are undefined.\""); } -//--------------------------------------------------------------------------- -// if (!x==3) <- Probably meant to be "x!=3" -//--------------------------------------------------------------------------- - -static bool isBool(const Variable* var) -{ - return(var && var->typeEndToken()->str() == "bool"); -} -static bool isNonBoolStdType(const Variable* var) -{ - return(var && var->typeEndToken()->isStandardType() && var->typeEndToken()->str() != "bool"); -} -void CheckOther::checkComparisonOfBoolWithInt() -{ - if (!_settings->isEnabled("warning")) - return; - - const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { - if (tok->next() && tok->next()->type() == Token::eComparisonOp && (!tok->previous() || !tok->previous()->isArithmeticalOp()) && (!tok->tokAt(3) || !tok->tokAt(3)->isArithmeticalOp())) { - const Token* const right = tok->tokAt(2); - if ((tok->varId() && right->isNumber()) || (tok->isNumber() && right->varId())) { // Comparing variable with number - const Token* varTok = tok; - const Token* numTok = right; - if (tok->isNumber() && right->varId()) // num with var - std::swap(varTok, numTok); - if (isBool(varTok->variable()) && // Variable has to be a boolean - ((tok->strAt(1) != "==" && tok->strAt(1) != "!=") || - (MathLib::toLongNumber(numTok->str()) != 0 && MathLib::toLongNumber(numTok->str()) != 1))) { // == 0 and != 0 are allowed, for C also == 1 and != 1 - comparisonOfBoolWithIntError(varTok, numTok->str(), tok->strAt(1) == "==" || tok->strAt(1) == "!="); - } - } else if (tok->isBoolean() && right->varId()) { // Comparing boolean constant with variable - if (isNonBoolStdType(right->variable())) { // Variable has to be of non-boolean standard type - comparisonOfBoolWithIntError(right, tok->str(), false); - } else if (tok->strAt(1) != "==" && tok->strAt(1) != "!=") { - comparisonOfBoolWithInvalidComparator(right, tok->str()); - } - } else if (tok->varId() && right->isBoolean()) { // Comparing variable with boolean constant - if (isNonBoolStdType(tok->variable())) { // Variable has to be of non-boolean standard type - comparisonOfBoolWithIntError(tok, right->str(), false); - } else if (tok->strAt(1) != "==" && tok->strAt(1) != "!=") { - comparisonOfBoolWithInvalidComparator(right, tok->str()); - } - } else if (tok->isNumber() && right->isBoolean()) { // number constant with boolean constant - comparisonOfBoolWithIntError(tok, right->str(), false); - } else if (tok->isBoolean() && right->isNumber()) { // number constant with boolean constant - comparisonOfBoolWithIntError(tok, tok->str(), false); - } else if (tok->varId() && right->varId()) { // Comparing two variables, one of them boolean, one of them integer - const Variable* var1 = right->variable(); - const Variable* var2 = tok->variable(); - if (isBool(var1) && isNonBoolStdType(var2)) // Comparing boolean with non-bool standard type - comparisonOfBoolWithIntError(tok, var1->name(), false); - else if (isNonBoolStdType(var1) && isBool(var2)) // Comparing non-bool standard type with boolean - comparisonOfBoolWithIntError(tok, var2->name(), false); - } - } - } - } -} - -void CheckOther::comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1) -{ - if (n0o1) - reportError(tok, Severity::warning, "comparisonOfBoolWithInt", - "Comparison of a boolean with an integer that is neither 1 nor 0.\n" - "The expression '" + expression + "' is of type 'bool' " - "and it is compared against an integer value that is " - "neither 1 nor 0."); - else - reportError(tok, Severity::warning, "comparisonOfBoolWithInt", - "Comparison of a boolean with an integer.\n" - "The expression '" + expression + "' is of type 'bool' " - "and it is compared against an integer value."); -} - -void CheckOther::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression) -{ - reportError(tok, Severity::warning, "comparisonOfBoolWithInvalidComparator", - "Comparison of a boolean value using relational operator (<, >, <= or >=).\n" - "The result of the expression '" + expression + "' is of type 'bool'. " - "Comparing 'bool' value using relational (<, >, <= or >=)" - " operator could cause unexpected results."); -} - //--------------------------------------------------------------------------- // Find consecutive return, break, continue, goto or throw statements. e.g.: // break; break; @@ -2580,137 +2418,6 @@ void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& va "unusedScopedObject", "Instance of '" + varname + "' object is destroyed immediately."); } -//------------------------------------------------------------------------------- -// Comparing functions which are returning value of type bool -//------------------------------------------------------------------------------- - -void CheckOther::checkComparisonOfFuncReturningBool() -{ - if (!_settings->isEnabled("style")) - return; - - if (!_tokenizer->isCPP()) - return; - - const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase(); - - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { - if (tok->type() != Token::eComparisonOp || tok->str() == "==" || tok->str() == "!=") - continue; - const Token *first_token; - bool first_token_func_of_type_bool = false; - if (tok->strAt(-1) == ")") { - first_token = tok->previous()->link()->previous(); - } else { - first_token = tok->previous(); - } - if (Token::Match(first_token, "%var% (") && !Token::Match(first_token->previous(), "::|.")) { - const Function* func = first_token->function(); - if (func && func->tokenDef && func->tokenDef->strAt(-1) == "bool") { - first_token_func_of_type_bool = true; - } - } - - Token *second_token = tok->next(); - bool second_token_func_of_type_bool = false; - while (second_token->str()=="!") { - second_token = second_token->next(); - } - if (Token::Match(second_token, "%var% (") && !Token::Match(second_token->previous(), "::|.")) { - const Function* func = second_token->function(); - if (func && func->tokenDef && func->tokenDef->strAt(-1) == "bool") { - second_token_func_of_type_bool = true; - } - } - - if ((first_token_func_of_type_bool == true) && (second_token_func_of_type_bool == true)) { - comparisonOfTwoFuncsReturningBoolError(first_token->next(), first_token->str(), second_token->str()); - } else if (first_token_func_of_type_bool == true) { - comparisonOfFuncReturningBoolError(first_token->next(), first_token->str()); - } else if (second_token_func_of_type_bool == true) { - comparisonOfFuncReturningBoolError(second_token->previous(), second_token->str()); - } - } - } -} - -void CheckOther::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression) -{ - reportError(tok, Severity::style, "comparisonOfFuncReturningBoolError", - "Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n" - "The return type of function '" + expression + "' is 'bool' " - "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)" - " operator could cause unexpected results."); -} - -void CheckOther::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2) -{ - reportError(tok, Severity::style, "comparisonOfTwoFuncsReturningBoolError", - "Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n" - "The return type of function '" + expression1 + "' and function '" + expression2 + "' is 'bool' " - "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)" - " operator could cause unexpected results."); -} - -//------------------------------------------------------------------------------- -// Comparison of bool with bool -//------------------------------------------------------------------------------- - -void CheckOther::checkComparisonOfBoolWithBool() -{ - // FIXME: This checking is "experimental" because of the false positives - // when self checking lib/tokenize.cpp (#2617) - if (!_settings->experimental) - return; - - if (!_settings->isEnabled("style")) - return; - - if (!_tokenizer->isCPP()) - return; - - const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); - - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { - if (tok->type() != Token::eComparisonOp || tok->str() == "==" || tok->str() == "!=") - continue; - bool first_token_bool = false; - bool second_token_bool = false; - - const Token *first_token = tok->previous(); - if (first_token->varId()) { - if (isBool(first_token->variable())) { - first_token_bool = true; - } - } - const Token *second_token = tok->next(); - if (second_token->varId()) { - if (isBool(second_token->variable())) { - second_token_bool = true; - } - } - if ((first_token_bool == true) && (second_token_bool == true)) { - comparisonOfBoolWithBoolError(first_token->next(), first_token->str()); - } - } - } -} - -void CheckOther::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression) -{ - reportError(tok, Severity::style, "comparisonOfBoolWithBoolError", - "Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n" - "The variable '" + expression + "' is of type 'bool' " - "and comparing 'bool' value using relational (<, >, <= or >=)" - " operator could cause unexpected results."); -} - //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void CheckOther::checkIncorrectStringCompare() @@ -3675,98 +3382,6 @@ void CheckOther::divideSizeofError(const Token *tok) "not the size of the memory area it points to.", true); } -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CheckOther::checkAssignBoolToPointer() -{ - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { - if (Token::Match(tok, "!!* %var% = %bool% ;")) { - const Variable *var1(tok->next()->variable()); - - // Is variable a pointer? - if (var1 && var1->isPointer()) - assignBoolToPointerError(tok->next()); - } - } - } -} - -void CheckOther::assignBoolToPointerError(const Token *tok) -{ - reportError(tok, Severity::error, "assignBoolToPointer", - "Boolean value assigned to pointer."); -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void CheckOther::checkComparisonOfBoolExpressionWithInt() -{ - if (!_settings->isEnabled("warning")) - return; - - const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase(); - - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { - // Skip template parameters - if (tok->str() == "<" && tok->link()) { - tok = tok->link(); - continue; - } - - const Token* numTok = 0; - const Token* opTok = 0; - char op = 0; - if (Token::Match(tok, "&&|%oror% %any% ) %comp% %any%")) { - numTok = tok->tokAt(4); - opTok = tok->tokAt(3); - if (Token::Match(opTok, "<|>")) - op = opTok->str()[0]; - } else if (Token::Match(tok, "%any% %comp% ( %any% &&|%oror%")) { - numTok = tok; - opTok = tok->next(); - if (Token::Match(opTok, "<|>")) - op = opTok->str()[0]=='>'?'<':'>'; - } - - else if (Token::Match(tok, "! %var% %comp% %any%")) { - numTok = tok->tokAt(3); - opTok = tok->tokAt(2); - if (Token::Match(opTok, "<|>")) - op = opTok->str()[0]; - } else if (Token::Match(tok, "%any% %comp% ! %var%")) { - numTok = tok; - opTok = tok->next(); - if (Token::Match(opTok, "<|>")) - op = opTok->str()[0]=='>'?'<':'>'; - } - - if (numTok && opTok) { - if (numTok->isNumber()) { - if (((numTok->str() != "0" && numTok->str() != "1") || !Token::Match(opTok, "!=|==")) && !((op == '<' && numTok->str() == "1") || (op == '>' && numTok->str() == "0"))) - comparisonOfBoolExpressionWithIntError(tok, true); - } else if (isNonBoolStdType(numTok->variable())) - comparisonOfBoolExpressionWithIntError(tok, false); - } - } - } -} - -void CheckOther::comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1) -{ - if (n0o1) - reportError(tok, Severity::warning, "compareBoolExpressionWithInt", - "Comparison of a boolean expression with an integer other than 0 or 1."); - else - reportError(tok, Severity::warning, "compareBoolExpressionWithInt", - "Comparison of a boolean expression with an integer."); -} //--------------------------------------------------------------------------- @@ -3965,7 +3580,7 @@ void CheckOther::checkIncompleteArrayFill() if (MathLib::toLongNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) { unsigned int size = _tokenizer->sizeOfType(var->typeStartToken()); - if ((size != 1 && size != 100 && size != 0) || var->typeEndToken()->str() == "*") { + if ((size != 1 && size != 100 && size != 0) || var->isPointer()) { if (warning) incompleteArrayFillError(tok, var->name(), tok->str(), false); } else if (var->typeStartToken()->str() == "bool" && portability) // sizeof(bool) is not 1 on all platforms diff --git a/lib/checkother.h b/lib/checkother.h index edcd3c762..67e173e24 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -75,8 +75,6 @@ public: checkOther.checkSuspiciousSemicolon(); checkOther.checkVariableScope(); checkOther.clarifyCondition(); // not simplified because ifAssign - checkOther.checkComparisonOfBoolExpressionWithInt(); - checkOther.checkComparisonOfBoolWithInt(); checkOther.checkSignOfUnsignedVariable(); // don't ignore casts (#3574) checkOther.checkIncompleteArrayFill(); checkOther.checkSuspiciousStringCompare(); @@ -103,18 +101,13 @@ public: checkOther.redundantGetAndSetUserId(); checkOther.checkIncorrectLogicOperator(); checkOther.checkMisusedScopedObject(); - checkOther.checkComparisonOfFuncReturningBool(); - checkOther.checkComparisonOfBoolWithBool(); checkOther.checkMemsetZeroBytes(); checkOther.checkIncorrectStringCompare(); - checkOther.checkIncrementBoolean(); checkOther.checkSwitchCaseFallThrough(); checkOther.checkAlwaysTrueOrFalseStringCompare(); checkOther.checkModuloAlwaysTrueFalse(); checkOther.checkPipeParameterSize(); - checkOther.checkAssignBoolToPointer(); - checkOther.checkBitwiseOnBoolean(); checkOther.checkInvalidFree(); checkOther.checkDoubleFree(); checkOther.checkRedundantCopy(); @@ -217,12 +210,6 @@ public: /** @brief %Check for objects that are destroyed immediately */ void checkMisusedScopedObject(); - /** @brief %Check for comparison of function returning bool*/ - void checkComparisonOfFuncReturningBool(); - - /** @brief %Check for comparison of variable of type bool*/ - void checkComparisonOfBoolWithBool(); - /** @brief %Check for filling zero bytes with memset() */ void checkMemsetZeroBytes(); @@ -241,12 +228,6 @@ public: /** @brief %Check for comparison of a string literal with a char* variable */ void checkSuspiciousStringCompare(); - /** @brief %Check for using postfix increment on bool */ - void checkIncrementBoolean(); - - /** @brief %Check for suspicious comparison of a bool and a non-zero (and non-one) value (e.g. "if (!x==4)") */ - void checkComparisonOfBoolWithInt(); - /** @brief %Check for suspicious code where multiple if have the same expression (e.g "if (a) { } else if (a) { }") */ void checkDuplicateIf(); @@ -265,18 +246,9 @@ public: /** @brief %Check for code that gets never executed, such as duplicate break statements */ void checkUnreachableCode(); - /** @brief assigning bool to pointer */ - void checkAssignBoolToPointer(); - /** @brief %Check for testing sign of unsigned variable */ void checkSignOfUnsignedVariable(); - /** @brief %Check for using bool in bitwise expression */ - void checkBitwiseOnBoolean(); - - /** @brief %Check for comparing a bool expression with an integer other than 0 or 1 */ - void checkComparisonOfBoolExpressionWithInt(); - /** @brief %Check for suspicious use of semicolon */ void checkSuspiciousSemicolon(); @@ -353,18 +325,12 @@ private: void incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always); void redundantConditionError(const Token *tok, const std::string &text); void misusedScopeObjectError(const Token *tok, const std::string &varname); - void comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression); - void comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2); - void comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression); void memsetZeroBytesError(const Token *tok, const std::string &varname); void sizeofForArrayParameterError(const Token *tok); void sizeofForPointerError(const Token *tok, const std::string &varname); void sizeofForNumericParameterError(const Token *tok); void incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string); void incorrectStringBooleanError(const Token *tok, const std::string& string); - void incrementBooleanError(const Token *tok); - void comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1); - void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression); void duplicateIfError(const Token *tok1, const Token *tok2); void duplicateBranchError(const Token *tok1, const Token *tok2); void duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op); @@ -373,13 +339,10 @@ private: void suspiciousStringCompareError(const Token* tok, const std::string& var); void duplicateBreakError(const Token *tok, bool inconclusive); void unreachableCodeError(const Token* tok, bool inconclusive); - void assignBoolToPointerError(const Token *tok); void unsignedLessThanZeroError(const Token *tok, const std::string &varname, bool inconclusive); void pointerLessThanZeroError(const Token *tok, bool inconclusive); void unsignedPositiveError(const Token *tok, const std::string &varname, bool inconclusive); void pointerPositiveError(const Token *tok, bool inconclusive); - void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op); - void comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1); void SuspiciousSemicolonError(const Token *tok); void doubleCloseDirError(const Token *tok, const std::string &varname); void moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal); @@ -392,15 +355,11 @@ private: CheckOther c(0, settings, errorLogger); // error - c.assignBoolToPointerError(0); c.sprintfOverlappingDataError(0, "varname"); c.udivError(0, false); c.zerodivError(0); c.mathfunctionCallError(0); c.misusedScopeObjectError(NULL, "varname"); - c.comparisonOfFuncReturningBoolError(0, "func_name"); - c.comparisonOfTwoFuncsReturningBoolError(0, "func_name1", "func_name2"); - c.comparisonOfBoolWithBoolError(0, "var_name"); c.sizeofForArrayParameterError(0); c.sizeofForPointerError(0, "varname"); c.sizeofForNumericParameterError(0); @@ -446,8 +405,6 @@ private: c.incorrectStringCompareError(0, "substr", "\"Hello World\""); c.suspiciousStringCompareError(0, "foo"); c.incorrectStringBooleanError(0, "\"Hello World\""); - c.incrementBooleanError(0); - c.comparisonOfBoolWithIntError(0, "varname", true); c.duplicateIfError(0, 0); c.duplicateBranchError(0, 0); c.duplicateExpressionError(0, 0, "&&"); @@ -459,8 +416,6 @@ private: c.unsignedPositiveError(0, "varname", false); c.pointerLessThanZeroError(0, false); c.pointerPositiveError(0, false); - c.bitwiseOnBooleanError(0, "varname", "&&"); - c.comparisonOfBoolExpressionWithIntError(0, true); c.SuspiciousSemicolonError(0); c.cctypefunctionCallError(0, "funname", "value"); c.moduloAlwaysTrueFalseError(0, "1"); @@ -520,11 +475,6 @@ private: "* Suspicious equality comparisons\n" "* mutual exclusion over || always evaluating to true\n" "* Clarify calculation with parentheses\n" - "* using increment on boolean\n" - "* comparison of a boolean with a non-zero integer\n" - "* comparison of a boolean expression with an integer other than 0 or 1\n" - "* comparison of a function returning boolean value using relational operator\n" - "* comparison of a boolean value with boolean value using relational operator\n" "* suspicious condition (assignment+comparison)\n" "* suspicious condition (runtime comparison of string literals)\n" "* suspicious condition (string literals as boolean)\n" @@ -533,7 +483,6 @@ private: "* unreachable code\n" "* testing if unsigned variable is negative\n" "* testing is unsigned variable is positive\n" - "* using bool in bitwise expression\n" "* Suspicious use of ; at the end of 'if/for/while' statement.\n" "* incorrect usage of functions from ctype library.\n" "* Comparisons of modulo results that are always true/false.\n" diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index db1a20f6b..7d2fe4bcf 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -38,6 +38,7 @@ + @@ -75,6 +76,7 @@ + diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters index f44d60a28..b6646dd44 100644 --- a/lib/cppcheck.vcxproj.filters +++ b/lib/cppcheck.vcxproj.filters @@ -113,6 +113,9 @@ Source Files + + Source Files + @@ -226,6 +229,9 @@ Header Files + + Header Files + diff --git a/test/testbool.cpp b/test/testbool.cpp new file mode 100644 index 000000000..006d9606a --- /dev/null +++ b/test/testbool.cpp @@ -0,0 +1,768 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2013 Daniel Marjamäki and 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 . + */ + + +#include "tokenize.h" +#include "checkbool.h" +#include "testsuite.h" +#include + +extern std::ostringstream errout; + +class TestBool : public TestFixture { +public: + TestBool() : TestFixture("TestBool") + { } + +private: + + + void run() { + TEST_CASE(bitwiseOnBoolean); // if (bool & bool) + TEST_CASE(incrementBoolean); + TEST_CASE(assignBoolToPointer); + + TEST_CASE(comparisonOfBoolExpressionWithInt1); + TEST_CASE(comparisonOfBoolExpressionWithInt2); + TEST_CASE(comparisonOfBoolExpressionWithInt3); + + TEST_CASE(comparisonOfBoolWithInt1); + TEST_CASE(comparisonOfBoolWithInt2); + TEST_CASE(comparisonOfBoolWithInt3); + TEST_CASE(comparisonOfBoolWithInt4); + TEST_CASE(comparisonOfBoolWithInt5); + TEST_CASE(comparisonOfBoolWithInt6); // #4224 - integer is casted to bool + + TEST_CASE(checkComparisonOfFuncReturningBool1); + TEST_CASE(checkComparisonOfFuncReturningBool2); + TEST_CASE(checkComparisonOfFuncReturningBool3); + TEST_CASE(checkComparisonOfFuncReturningBool4); + TEST_CASE(checkComparisonOfFuncReturningBool5); + TEST_CASE(checkComparisonOfFuncReturningBool6); + } + + void check(const char code[], bool experimental = false) { + // Clear the error buffer.. + errout.str(""); + + Settings settings; + settings.addEnabled("style"); + settings.addEnabled("warning"); + settings.inconclusive = true; + settings.experimental = experimental; + + // Tokenize.. + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + // Check... + CheckBool checkBool(&tokenizer, &settings, this); + checkBool.runChecks(&tokenizer, &settings, this); + + // Simplify token list.. + tokenizer.simplifyTokenList(); + checkBool.runSimplifiedChecks(&tokenizer, &settings, this); + } + + + void assignBoolToPointer() { + check("void foo(bool *p) {\n" + " p = false;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (error) Boolean value assigned to pointer.\n", errout.str()); + } + + void comparisonOfBoolExpressionWithInt1() { + check("void f(int x) {\n" + " if ((x && 0x0f)==6)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if ((x && 0x0f)==0)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if ((x || 0x0f)==6)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if ((x || 0x0f)==0)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if ((x & 0x0f)==6)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if ((x | 0x0f)==6)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + + check("void f(int x) {\n" + " if ((5 && x)==3)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if ((5 && x)==3 || (8 && x)==9)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if ((5 && x)!=3)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + + check("void f(int x) {\n" + " if ((5 && x) > 3)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if ((5 && x) > 0)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if ((5 && x) < 0)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if ((5 && x) < 1)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if ((5 && x) > 1)\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + + check("void f(int x) {\n" + " if (0 < (5 && x))\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if (0 > (5 && x))\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if (1 > (5 && x))\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if (1 < (5 && x))\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( x > false )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( false < x )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( x < false )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( false > x )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( x >= false )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( false >= x )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( x <= false )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("void f(bool x ) {\n" + " if ( false <= x )\n" + " a++;\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); + + check("typedef int (*func)(bool invert);\n" + "void x(int, func f);\n" + "void foo(int error) {\n" + " if (error == ABC) { }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void comparisonOfBoolExpressionWithInt2() { + check("void f(int x) {\n" + " if (!x == 10) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if (!x != 10) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if (x != 10) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if (10 == !x) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x) {\n" + " if (10 != !x) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); + + check("void f(int x, int y) {\n" + " if (y != !x) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer.\n", errout.str()); + + check("void f(int x, bool y) {\n" + " if (y != !x) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(int x) {\n" + " if (10 != x) {\n" + " printf(\"x not equal to 10\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void comparisonOfBoolExpressionWithInt3() { + check("int f(int x) {\n" + " return t<0>() && x;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void checkComparisonOfFuncReturningBool1() { + check("void f(){\n" + " int temp = 4;\n" + " if(compare1(temp) > compare2(temp)){\n" + " printf(\"foo\");\n" + " }\n" + "}\n" + "bool compare1(int temp){\n" + " if(temp==4){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}\n" + "bool compare2(int temp){\n" + " if(temp==4){\n" + " return false;\n" + " }\n" + " else\n" + " return true;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); + } + + void checkComparisonOfFuncReturningBool2() { + check("void f(){\n" + " int temp = 4;\n" + " bool a = true;\n" + " if(compare(temp) > a){\n" + " printf(\"foo\");\n" + " }\n" + "}\n" + "bool compare(int temp){\n" + " if(temp==4){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); + } + + void checkComparisonOfFuncReturningBool3() { + check("void f(){\n" + " int temp = 4;\n" + " if(compare(temp) > temp){\n" + " printf(\"foo\");\n" + " }\n" + "}\n" + "bool compare(int temp){\n" + " if(temp==4){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); + } + + void checkComparisonOfFuncReturningBool4() { + check("void f(){\n" + " int temp = 4;\n" + " bool b = compare2(6);\n" + " if(compare1(temp)> b){\n" + " printf(\"foo\");\n" + " }\n" + "}\n" + "bool compare1(int temp){\n" + " if(temp==4){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}\n" + "bool compare2(int temp){\n" + " if(temp == 5){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); + } + + void checkComparisonOfFuncReturningBool5() { + check("void f(){\n" + " int temp = 4;\n" + " if(compare1(temp) > !compare2(temp)){\n" + " printf(\"foo\");\n" + " }\n" + "}\n" + "bool compare1(int temp){\n" + " if(temp==4){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}\n" + "bool compare2(int temp){\n" + " if(temp==4){\n" + " return false;\n" + " }\n" + " else\n" + " return true;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); + } + + void checkComparisonOfFuncReturningBool6() { + check("int compare1(int temp);\n" + "namespace Foo {\n" + " bool compare1(int temp);\n" + "}\n" + "void f(){\n" + " int temp = 4;\n" + " if(compare1(temp) > compare2(temp)){\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("namespace Foo {\n" + " bool compare1(int temp);\n" + "}\n" + "int compare1(int temp);\n" + "void f(){\n" + " int temp = 4;\n" + " if(compare1(temp) > compare2(temp)){\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("int compare1(int temp);\n" + "namespace Foo {\n" + " bool compare1(int temp);\n" + " void f(){\n" + " int temp = 4;\n" + " if(compare1(temp) > compare2(temp)){\n" + " printf(\"foo\");\n" + " }\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:6]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); + + check("int compare1(int temp);\n" + "namespace Foo {\n" + " bool compare1(int temp);\n" + " void f(){\n" + " int temp = 4;\n" + " if(::compare1(temp) > compare2(temp)){\n" + " printf(\"foo\");\n" + " }\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("bool compare1(int temp);\n" + "void f(){\n" + " int temp = 4;\n" + " if(foo.compare1(temp) > compare2(temp)){\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void checkComparisonOfBoolWithBool() { + const char code[] = "void f(){\n" + " int temp = 4;\n" + " bool b = compare2(6);\n" + " bool a = compare1(4);\n" + " if(b > a){\n" + " printf(\"foo\");\n" + " }\n" + "}\n" + "bool compare1(int temp){\n" + " if(temp==4){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}\n" + "bool compare2(int temp){\n" + " if(temp == 5){\n" + " return true;\n" + " }\n" + " else\n" + " return false;\n" + "}\n"; + check(code, true); + ASSERT_EQUALS("[test.cpp:5]: (style) Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); + check(code, false); + ASSERT_EQUALS("", errout.str()); + } + + void bitwiseOnBoolean() { // 3062 + check("void f(_Bool a, _Bool b) {\n" + " if(a & b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); + + check("void f(_Bool a, _Bool b) {\n" + " if(a | b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); + + check("void f(bool a, bool b) {\n" + " if(a & !b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); + + check("void f(bool a, bool b) {\n" + " if(a | !b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); + + check("bool a, b;\n" + "void f() {\n" + " if(a & b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); + + check("bool a, b;\n" + "void f() {\n" + " if(a & !b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); + + check("bool a, b;\n" + "void f() {\n" + " if(a | b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); + + check("bool a, b;\n" + "void f() {\n" + " if(a | !b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); + + check("void f(bool a, int b) {\n" + " if(a & b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); + + check("void f(int a, bool b) {\n" + " if(a & b) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'b' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); + + check("void f(int a, int b) {\n" + " if(a & b) {}\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(bool b) {\n" + " foo(bar, &b);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void incrementBoolean() { + check("bool bValue = true;\n" + "void f() { bValue++; }"); + ASSERT_EQUALS("[test.cpp:2]: (style) Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n", errout.str()); + + check("_Bool bValue = true;\n" + "void f() { bValue++; }"); + ASSERT_EQUALS("[test.cpp:2]: (style) Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n", errout.str()); + + check("void f(bool test){\n" + " test++;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style) Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n", errout.str()); + + check("void f(int test){\n" + " test++;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void comparisonOfBoolWithInt1() { + check("void f(bool x) {\n" + " if (x < 10) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); + + check("void f(bool x) {\n" + " if (10 >= x) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); + + check("void f(bool x) {\n" + " if (x != 0) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(bool x) {\n" // #3356 + " if (x == 1) {\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(bool x) {\n" + " if (x != 10) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer that is neither 1 nor 0.\n", errout.str()); + + check("void f(bool x) {\n" + " if (x == 10) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer that is neither 1 nor 0.\n", errout.str()); + + check("void f(bool x) {\n" + " if (x == 0) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("DensePropertyMap visited;"); // #4075 + ASSERT_EQUALS("", errout.str()); + } + + void comparisonOfBoolWithInt2() { + check("void f(bool x, int y) {\n" + " if (x == y) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); + + check("void f(int x, bool y) {\n" + " if (x == y) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); + + check("void f(bool x, bool y) {\n" + " if (x == y) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(bool x, fooClass y) {\n" + " if (x == y) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void comparisonOfBoolWithInt3() { + check("void f(int y) {\n" + " if (y > false) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); + + check("void f(int y) {\n" + " if (true == y) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); + + check("void f(bool y) {\n" + " if (y == true) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(bool y) {\n" + " if (false < 5) {\n" + " printf(\"foo\");\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); + } + + void comparisonOfBoolWithInt4() { + check("void f(int x) {\n" + " if (!x == 1) { }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void comparisonOfBoolWithInt5() { + check("void SetVisible(int index, bool visible) {\n" + " bool (SciTEBase::*ischarforsel)(char ch);\n" + " if (visible != GetVisible(index)) { }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void comparisonOfBoolWithInt6() { // #4224 - integer is casted to bool + check("void SetVisible(bool b, int i) {\n" + " if (b == (bool)i) { }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } +}; + +REGISTER_TEST(TestBool) diff --git a/test/testother.cpp b/test/testother.cpp index 2d384c926..98a479e2e 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -34,7 +34,6 @@ private: void run() { TEST_CASE(oppositeInnerCondition); - TEST_CASE(assignBoolToPointer); TEST_CASE(emptyBrackets); TEST_CASE(zeroDiv1); @@ -140,31 +139,9 @@ private: TEST_CASE(clarifyCondition4); // ticket #3110 TEST_CASE(clarifyCondition5); // #3609 CWinTraits.. TEST_CASE(clarifyCondition6); // #3818 - TEST_CASE(bitwiseOnBoolean); // if (bool & bool) - - TEST_CASE(comparisonOfBoolExpressionWithInt1); - TEST_CASE(comparisonOfBoolExpressionWithInt2); - TEST_CASE(comparisonOfBoolExpressionWithInt3); TEST_CASE(incorrectStringCompare); - TEST_CASE(incrementBoolean); - TEST_CASE(comparisonOfBoolWithInt1); - TEST_CASE(comparisonOfBoolWithInt2); - TEST_CASE(comparisonOfBoolWithInt3); - TEST_CASE(comparisonOfBoolWithInt4); - TEST_CASE(comparisonOfBoolWithInt5); - TEST_CASE(comparisonOfBoolWithInt6); // #4224 - integer is casted to bool - - TEST_CASE(checkComparisonOfFuncReturningBool1); - TEST_CASE(checkComparisonOfFuncReturningBool2); - TEST_CASE(checkComparisonOfFuncReturningBool3); - TEST_CASE(checkComparisonOfFuncReturningBool4); - TEST_CASE(checkComparisonOfFuncReturningBool5); - TEST_CASE(checkComparisonOfFuncReturningBool6); - - TEST_CASE(checkComparisonOfBoolWithBool); - TEST_CASE(duplicateIf); TEST_CASE(duplicateIf1); // ticket 3689 TEST_CASE(duplicateBranch); @@ -324,14 +301,6 @@ private: ASSERT_EQUALS("", errout.str()); } - - void assignBoolToPointer() { - check("void foo(bool *p) {\n" - " p = false;\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Boolean value assigned to pointer.\n", errout.str()); - } - void emptyBrackets() { check("{\n" "}"); @@ -3902,265 +3871,6 @@ private: ASSERT_EQUALS("", errout.str()); } - void comparisonOfBoolExpressionWithInt1() { - check("void f(int x) {\n" - " if ((x && 0x0f)==6)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if ((x && 0x0f)==0)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if ((x || 0x0f)==6)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if ((x || 0x0f)==0)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if ((x & 0x0f)==6)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if ((x | 0x0f)==6)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - - check("void f(int x) {\n" - " if ((5 && x)==3)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if ((5 && x)==3 || (8 && x)==9)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if ((5 && x)!=3)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - - check("void f(int x) {\n" - " if ((5 && x) > 3)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if ((5 && x) > 0)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if ((5 && x) < 0)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if ((5 && x) < 1)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if ((5 && x) > 1)\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - - check("void f(int x) {\n" - " if (0 < (5 && x))\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if (0 > (5 && x))\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if (1 > (5 && x))\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if (1 < (5 && x))\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( x > false )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( false < x )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( x < false )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( false > x )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( x >= false )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( false >= x )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( x <= false )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("void f(bool x ) {\n" - " if ( false <= x )\n" - " a++;\n" - "}\n" - ); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational operator (<, >, <= or >=).\n", errout.str()); - - check("typedef int (*func)(bool invert);\n" - "void x(int, func f);\n" - "void foo(int error) {\n" - " if (error == ABC) { }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void comparisonOfBoolExpressionWithInt2() { - check("void f(int x) {\n" - " if (!x == 10) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if (!x != 10) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if (x != 10) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if (10 == !x) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x) {\n" - " if (10 != !x) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer other than 0 or 1.\n", errout.str()); - - check("void f(int x, int y) {\n" - " if (y != !x) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean expression with an integer.\n", errout.str()); - - check("void f(int x, bool y) {\n" - " if (y != !x) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void f(int x) {\n" - " if (10 != x) {\n" - " printf(\"x not equal to 10\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void comparisonOfBoolExpressionWithInt3() { - check("int f(int x) {\n" - " return t<0>() && x;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - void memsetZeroBytes() { check("void f() {\n" " memset(p, 10, 0x0);\n" @@ -4313,202 +4023,6 @@ private: } - void checkComparisonOfFuncReturningBool1() { - check("void f(){\n" - " int temp = 4;\n" - " if(compare1(temp) > compare2(temp)){\n" - " printf(\"foo\");\n" - " }\n" - "}\n" - "bool compare1(int temp){\n" - " if(temp==4){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}\n" - "bool compare2(int temp){\n" - " if(temp==4){\n" - " return false;\n" - " }\n" - " else\n" - " return true;\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); - } - - void checkComparisonOfFuncReturningBool2() { - check("void f(){\n" - " int temp = 4;\n" - " bool a = true;\n" - " if(compare(temp) > a){\n" - " printf(\"foo\");\n" - " }\n" - "}\n" - "bool compare(int temp){\n" - " if(temp==4){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); - } - - void checkComparisonOfFuncReturningBool3() { - check("void f(){\n" - " int temp = 4;\n" - " if(compare(temp) > temp){\n" - " printf(\"foo\");\n" - " }\n" - "}\n" - "bool compare(int temp){\n" - " if(temp==4){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); - } - - void checkComparisonOfFuncReturningBool4() { - check("void f(){\n" - " int temp = 4;\n" - " bool b = compare2(6);\n" - " if(compare1(temp)> b){\n" - " printf(\"foo\");\n" - " }\n" - "}\n" - "bool compare1(int temp){\n" - " if(temp==4){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}\n" - "bool compare2(int temp){\n" - " if(temp == 5){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); - } - - void checkComparisonOfFuncReturningBool5() { - check("void f(){\n" - " int temp = 4;\n" - " if(compare1(temp) > !compare2(temp)){\n" - " printf(\"foo\");\n" - " }\n" - "}\n" - "bool compare1(int temp){\n" - " if(temp==4){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}\n" - "bool compare2(int temp){\n" - " if(temp==4){\n" - " return false;\n" - " }\n" - " else\n" - " return true;\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); - } - - void checkComparisonOfFuncReturningBool6() { - check("int compare1(int temp);\n" - "namespace Foo {\n" - " bool compare1(int temp);\n" - "}\n" - "void f(){\n" - " int temp = 4;\n" - " if(compare1(temp) > compare2(temp)){\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("namespace Foo {\n" - " bool compare1(int temp);\n" - "}\n" - "int compare1(int temp);\n" - "void f(){\n" - " int temp = 4;\n" - " if(compare1(temp) > compare2(temp)){\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("int compare1(int temp);\n" - "namespace Foo {\n" - " bool compare1(int temp);\n" - " void f(){\n" - " int temp = 4;\n" - " if(compare1(temp) > compare2(temp)){\n" - " printf(\"foo\");\n" - " }\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:6]: (style) Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); - - check("int compare1(int temp);\n" - "namespace Foo {\n" - " bool compare1(int temp);\n" - " void f(){\n" - " int temp = 4;\n" - " if(::compare1(temp) > compare2(temp)){\n" - " printf(\"foo\");\n" - " }\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("bool compare1(int temp);\n" - "void f(){\n" - " int temp = 4;\n" - " if(foo.compare1(temp) > compare2(temp)){\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void checkComparisonOfBoolWithBool() { - const char code[] = "void f(){\n" - " int temp = 4;\n" - " bool b = compare2(6);\n" - " bool a = compare1(4);\n" - " if(b > a){\n" - " printf(\"foo\");\n" - " }\n" - "}\n" - "bool compare1(int temp){\n" - " if(temp==4){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}\n" - "bool compare2(int temp){\n" - " if(temp == 5){\n" - " return true;\n" - " }\n" - " else\n" - " return false;\n" - "}\n"; - check(code, "test.cpp", true); - ASSERT_EQUALS("[test.cpp:5]: (style) Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); - check(code, "test.cpp"); - ASSERT_EQUALS("", errout.str()); - } - void sizeofForNumericParameter() { check("void f() {\n" " std::cout << sizeof(10) << std::endl;\n" @@ -4788,72 +4302,6 @@ private: ASSERT_EQUALS("", errout.str()); } - void bitwiseOnBoolean() { // 3062 - check("void f(_Bool a, _Bool b) {\n" - " if(a & b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); - - check("void f(_Bool a, _Bool b) {\n" - " if(a | b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); - - check("void f(bool a, bool b) {\n" - " if(a & !b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); - - check("void f(bool a, bool b) {\n" - " if(a | !b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); - - check("bool a, b;\n" - "void f() {\n" - " if(a & b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); - - check("bool a, b;\n" - "void f() {\n" - " if(a & !b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); - - check("bool a, b;\n" - "void f() {\n" - " if(a | b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); - - check("bool a, b;\n" - "void f() {\n" - " if(a | !b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '||'?\n", errout.str()); - - check("void f(bool a, int b) {\n" - " if(a & b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'a' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); - - check("void f(int a, bool b) {\n" - " if(a & b) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Boolean variable 'b' is used in bitwise operation. Did you mean '&&'?\n", errout.str()); - - check("void f(int a, int b) {\n" - " if(a & b) {}\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void f(bool b) {\n" - " foo(bar, &b);\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - void incorrectStringCompare() { check("int f() {\n" " return test.substr( 0 , 4 ) == \"Hello\" ? : 0 : 1 ;\n" @@ -4932,161 +4380,6 @@ private: } - void incrementBoolean() { - check("bool bValue = true;\n" - "void f() { bValue++; }"); - ASSERT_EQUALS("[test.cpp:2]: (style) Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n", errout.str()); - - check("_Bool bValue = true;\n" - "void f() { bValue++; }"); - ASSERT_EQUALS("[test.cpp:2]: (style) Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n", errout.str()); - - check("void f(bool test){\n" - " test++;\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (style) Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n", errout.str()); - - check("void f(int test){\n" - " test++;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void comparisonOfBoolWithInt1() { - check("void f(bool x) {\n" - " if (x < 10) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); - - check("void f(bool x) {\n" - " if (10 >= x) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); - - check("void f(bool x) {\n" - " if (x != 0) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void f(bool x) {\n" // #3356 - " if (x == 1) {\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void f(bool x) {\n" - " if (x != 10) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer that is neither 1 nor 0.\n", errout.str()); - - check("void f(bool x) {\n" - " if (x == 10) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer that is neither 1 nor 0.\n", errout.str()); - - check("void f(bool x) {\n" - " if (x == 0) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("DensePropertyMap visited;"); // #4075 - ASSERT_EQUALS("", errout.str()); - } - - void comparisonOfBoolWithInt2() { - check("void f(bool x, int y) {\n" - " if (x == y) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); - - check("void f(int x, bool y) {\n" - " if (x == y) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); - - check("void f(bool x, bool y) {\n" - " if (x == y) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void f(bool x, fooClass y) {\n" - " if (x == y) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void comparisonOfBoolWithInt3() { - check("void f(int y) {\n" - " if (y > false) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); - - check("void f(int y) {\n" - " if (true == y) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); - - check("void f(bool y) {\n" - " if (y == true) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void f(bool y) {\n" - " if (false < 5) {\n" - " printf(\"foo\");\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean with an integer.\n", errout.str()); - } - - void comparisonOfBoolWithInt4() { - check("void f(int x) {\n" - " if (!x == 1) { }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void comparisonOfBoolWithInt5() { - check("void SetVisible(int index, bool visible) {\n" - " bool (SciTEBase::*ischarforsel)(char ch);\n" - " if (visible != GetVisible(index)) { }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void comparisonOfBoolWithInt6() { // #4224 - integer is casted to bool - check("void SetVisible(bool b, int i) {\n" - " if (b == (bool)i) { }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - void duplicateIf() { check("void f(int a, int &b) {\n" " if (a) { b = 1; }\n" diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj index 3b3223bfe..204318eb7 100644 --- a/test/testrunner.vcxproj +++ b/test/testrunner.vcxproj @@ -33,6 +33,7 @@ + diff --git a/test/testrunner.vcxproj.filters b/test/testrunner.vcxproj.filters index 77fcfda72..6d3b86624 100644 --- a/test/testrunner.vcxproj.filters +++ b/test/testrunner.vcxproj.filters @@ -166,6 +166,9 @@ Source Files + + Source Files +