Fixed #3233 (false positive: (style) Checking if unsigned variable 'i' is less than zero.)
This commit is contained in:
parent
95851454cc
commit
fa076598ad
|
@ -2558,6 +2558,10 @@ void CheckOther::checkSignOfUnsignedVariable()
|
||||||
if (!_settings->isEnabled("style"))
|
if (!_settings->isEnabled("style"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const bool inconclusive = _tokenizer->codeWithTemplates();
|
||||||
|
if (inconclusive && !_settings->inconclusive)
|
||||||
|
return;
|
||||||
|
|
||||||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
|
||||||
std::list<Scope>::const_iterator scope;
|
std::list<Scope>::const_iterator scope;
|
||||||
|
@ -2572,36 +2576,54 @@ void CheckOther::checkSignOfUnsignedVariable()
|
||||||
if (Token::Match(tok, ";|(|&&|%oror% %var% <|<= 0 ;|)|&&|%oror%") && tok->next()->varId()) {
|
if (Token::Match(tok, ";|(|&&|%oror% %var% <|<= 0 ;|)|&&|%oror%") && tok->next()->varId()) {
|
||||||
const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
|
const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
|
||||||
if (var && var->typeEndToken()->isUnsigned())
|
if (var && var->typeEndToken()->isUnsigned())
|
||||||
unsignedLessThanZeroError(tok->next(), tok->next()->str());
|
unsignedLessThanZeroError(tok->next(), tok->next()->str(), inconclusive);
|
||||||
} else if (Token::Match(tok, ";|(|&&|%oror% 0 > %var% ;|)|&&|%oror%") && tok->tokAt(3)->varId()) {
|
} else if (Token::Match(tok, ";|(|&&|%oror% 0 > %var% ;|)|&&|%oror%") && tok->tokAt(3)->varId()) {
|
||||||
const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
|
const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
|
||||||
if (var && var->typeEndToken()->isUnsigned())
|
if (var && var->typeEndToken()->isUnsigned())
|
||||||
unsignedLessThanZeroError(tok->tokAt(3), tok->strAt(3));
|
unsignedLessThanZeroError(tok->tokAt(3), tok->strAt(3), inconclusive);
|
||||||
} else if (Token::Match(tok, ";|(|&&|%oror% 0 <= %var% ;|)|&&|%oror%") && tok->tokAt(3)->varId()) {
|
} else if (Token::Match(tok, ";|(|&&|%oror% 0 <= %var% ;|)|&&|%oror%") && tok->tokAt(3)->varId()) {
|
||||||
const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
|
const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
|
||||||
if (var && var->typeEndToken()->isUnsigned())
|
if (var && var->typeEndToken()->isUnsigned())
|
||||||
unsignedPositiveError(tok->tokAt(3), tok->strAt(3));
|
unsignedPositiveError(tok->tokAt(3), tok->strAt(3), inconclusive);
|
||||||
} else if (Token::Match(tok, ";|(|&&|%oror% %var% >= 0 ;|)|&&|%oror%") && tok->next()->varId()) {
|
} else if (Token::Match(tok, ";|(|&&|%oror% %var% >= 0 ;|)|&&|%oror%") && tok->next()->varId()) {
|
||||||
const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
|
const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
|
||||||
if (var && var->typeEndToken()->isUnsigned())
|
if (var && var->typeEndToken()->isUnsigned())
|
||||||
unsignedPositiveError(tok->next(), tok->next()->str());
|
unsignedPositiveError(tok->next(), tok->next()->str(), inconclusive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckOther::unsignedLessThanZeroError(const Token *tok, const std::string &varname)
|
void CheckOther::unsignedLessThanZeroError(const Token *tok, const std::string &varname, bool inconclusive)
|
||||||
{
|
{
|
||||||
|
if (inconclusive) {
|
||||||
|
reportInconclusiveError(tok, Severity::style, "unsignedLessThanZero",
|
||||||
|
"Checking if unsigned variable '" + varname + "' is less than zero. This might be a false warning.\n"
|
||||||
|
"Checking if unsigned variable '" + varname + "' is less than zero. An unsigned "
|
||||||
|
"variable will never be negative so it is either pointless or an error to check if it is. "
|
||||||
|
"It's not known if the used constant is a template parameter or not and therefore "
|
||||||
|
"this message might be a false warning");
|
||||||
|
} else {
|
||||||
reportError(tok, Severity::style, "unsignedLessThanZero",
|
reportError(tok, Severity::style, "unsignedLessThanZero",
|
||||||
"Checking if unsigned variable '" + varname + "' is less than zero.\n"
|
"Checking if unsigned variable '" + varname + "' is less than zero.\n"
|
||||||
"An unsigned variable will never be negative so it is either pointless or "
|
"An unsigned variable will never be negative so it is either pointless or "
|
||||||
"an error to check if it is.");
|
"an error to check if it is.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckOther::unsignedPositiveError(const Token *tok, const std::string &varname)
|
void CheckOther::unsignedPositiveError(const Token *tok, const std::string &varname, bool inconclusive)
|
||||||
{
|
{
|
||||||
|
if (inconclusive) {
|
||||||
|
reportInconclusiveError(tok, Severity::style, "unsignedPositive",
|
||||||
|
"Checking if unsigned variable '" + varname + "' is positive is always true. This might be a false warning.\n"
|
||||||
|
"Checking if unsigned variable '" + varname + "' is positive is always true. "
|
||||||
|
"An unsigned variable will always be positive so it is either pointless or "
|
||||||
|
"an error to check if it is. It's not known if the used constant is a "
|
||||||
|
"template parameter or not and therefore this message might be a false warning");
|
||||||
|
} else {
|
||||||
reportError(tok, Severity::style, "unsignedPositive",
|
reportError(tok, Severity::style, "unsignedPositive",
|
||||||
"Checking if unsigned variable '" + varname + "' is positive is always true.\n"
|
"Checking if unsigned variable '" + varname + "' is positive is always true.\n"
|
||||||
"An unsigned variable will always be positive so it is either pointless or "
|
"An unsigned variable will always be positive so it is either pointless or "
|
||||||
"an error to check if it is.");
|
"an error to check if it is.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,8 +289,8 @@ public:
|
||||||
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
||||||
void duplicateBreakError(const Token *tok);
|
void duplicateBreakError(const Token *tok);
|
||||||
void assignBoolToPointerError(const Token *tok);
|
void assignBoolToPointerError(const Token *tok);
|
||||||
void unsignedLessThanZeroError(const Token *tok, const std::string &varname);
|
void unsignedLessThanZeroError(const Token *tok, const std::string &varname, bool inconclusive);
|
||||||
void unsignedPositiveError(const Token *tok, const std::string &varname);
|
void unsignedPositiveError(const Token *tok, const std::string &varname, bool inconclusive);
|
||||||
void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op);
|
void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op);
|
||||||
void comparisonOfBoolExpressionWithIntError(const Token *tok);
|
void comparisonOfBoolExpressionWithIntError(const Token *tok);
|
||||||
void SuspiciousSemicolonError(const Token *tok);
|
void SuspiciousSemicolonError(const Token *tok);
|
||||||
|
@ -343,8 +343,8 @@ public:
|
||||||
c.alwaysTrueFalseStringCompareError(0, "str1", "str2");
|
c.alwaysTrueFalseStringCompareError(0, "str1", "str2");
|
||||||
c.alwaysTrueStringVariableCompareError(0, "varname1", "varname2");
|
c.alwaysTrueStringVariableCompareError(0, "varname1", "varname2");
|
||||||
c.duplicateBreakError(0);
|
c.duplicateBreakError(0);
|
||||||
c.unsignedLessThanZeroError(0, "varname");
|
c.unsignedLessThanZeroError(0, "varname", false);
|
||||||
c.unsignedPositiveError(0, "varname");
|
c.unsignedPositiveError(0, "varname", false);
|
||||||
c.bitwiseOnBooleanError(0, "varname", "&&");
|
c.bitwiseOnBooleanError(0, "varname", "&&");
|
||||||
c.comparisonOfBoolExpressionWithIntError(0);
|
c.comparisonOfBoolExpressionWithIntError(0);
|
||||||
c.SuspiciousSemicolonError(0);
|
c.SuspiciousSemicolonError(0);
|
||||||
|
|
|
@ -3527,12 +3527,13 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (warning) Passing sizeof(pointer) as the last argument to strncmp.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (warning) Passing sizeof(pointer) as the last argument to strncmp.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_signOfUnsignedVariable(const char code[]) {
|
void check_signOfUnsignedVariable(const char code[], bool inconclusive=false) {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.addEnabled("style");
|
settings.addEnabled("style");
|
||||||
|
settings.inconclusive = inconclusive;
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
@ -3753,6 +3754,19 @@ private:
|
||||||
" return false;\n"
|
" return false;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
// #3233 - FP when template is used (template parameter is numeric constant)
|
||||||
|
{
|
||||||
|
const char code[] =
|
||||||
|
"template<int n> void foo(unsigned int x) {\n"
|
||||||
|
" if (x <= n);\n"
|
||||||
|
"}\n"
|
||||||
|
"foo<0>();";
|
||||||
|
check_signOfUnsignedVariable(code, false);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
check_signOfUnsignedVariable(code, true);
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) Checking if unsigned variable 'x' is less than zero. This might be a false warning.\n", errout.str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkForSuspiciousSemicolon1() {
|
void checkForSuspiciousSemicolon1() {
|
||||||
|
|
Loading…
Reference in New Issue