constStatementError: don't warn for casts with possible side effects,… (#3885)
* constStatementError: don't warn for casts with possible side effects, handle bool constants * Recursive call, add tests * Restore test * Don't warn for C++ casts to void * Don't warn for cast to void*
This commit is contained in:
parent
ffd9f9a93f
commit
705931266c
|
@ -1739,7 +1739,7 @@ static bool isVarDeclOp(const Token* tok)
|
||||||
return isType(typetok, Token::Match(vartok, "%var%"));
|
return isType(typetok, Token::Match(vartok, "%var%"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isConstStatement(const Token *tok)
|
static bool isConstStatement(const Token *tok, bool cpp)
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1759,11 +1759,13 @@ static bool isConstStatement(const Token *tok)
|
||||||
if (Token::simpleMatch(tok->previous(), "sizeof ("))
|
if (Token::simpleMatch(tok->previous(), "sizeof ("))
|
||||||
return true;
|
return true;
|
||||||
if (isCPPCast(tok))
|
if (isCPPCast(tok))
|
||||||
return isConstStatement(tok->astOperand2());
|
return isWithoutSideEffects(cpp, tok) && isConstStatement(tok->astOperand2(), cpp);
|
||||||
|
else if (tok->isCast())
|
||||||
|
return isWithoutSideEffects(cpp, tok->astOperand1()) && isConstStatement(tok->astOperand1(), cpp);
|
||||||
if (Token::Match(tok, "( %type%"))
|
if (Token::Match(tok, "( %type%"))
|
||||||
return isConstStatement(tok->astOperand1());
|
return isConstStatement(tok->astOperand1(), cpp);
|
||||||
if (Token::simpleMatch(tok, ","))
|
if (Token::simpleMatch(tok, ","))
|
||||||
return isConstStatement(tok->astOperand2());
|
return isConstStatement(tok->astOperand2(), cpp);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1771,6 +1773,8 @@ static bool isVoidStmt(const Token *tok)
|
||||||
{
|
{
|
||||||
if (Token::simpleMatch(tok, "( void"))
|
if (Token::simpleMatch(tok, "( void"))
|
||||||
return true;
|
return true;
|
||||||
|
if (isCPPCast(tok) && tok->astOperand1() && Token::Match(tok->astOperand1()->next(), "< void *| >"))
|
||||||
|
return true;
|
||||||
const Token *tok2 = tok;
|
const Token *tok2 = tok;
|
||||||
while (tok2->astOperand1())
|
while (tok2->astOperand1())
|
||||||
tok2 = tok2->astOperand1();
|
tok2 = tok2->astOperand1();
|
||||||
|
@ -1838,7 +1842,7 @@ void CheckOther::checkIncompleteStatement()
|
||||||
// Skip statement expressions
|
// Skip statement expressions
|
||||||
if (Token::simpleMatch(rtok, "; } )"))
|
if (Token::simpleMatch(rtok, "; } )"))
|
||||||
continue;
|
continue;
|
||||||
if (!isConstStatement(tok))
|
if (!isConstStatement(tok, mTokenizer->isCPP()))
|
||||||
continue;
|
continue;
|
||||||
if (isVoidStmt(tok))
|
if (isVoidStmt(tok))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1864,8 +1868,14 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type,
|
||||||
msg = "Found suspicious operator '" + tok->str() + "'";
|
msg = "Found suspicious operator '" + tok->str() + "'";
|
||||||
else if (Token::Match(tok, "%var%"))
|
else if (Token::Match(tok, "%var%"))
|
||||||
msg = "Unused variable value '" + tok->str() + "'";
|
msg = "Unused variable value '" + tok->str() + "'";
|
||||||
else if (Token::Match(valueTok, "%str%|%num%"))
|
else if (Token::Match(valueTok, "%str%|%num%|%bool%")) {
|
||||||
msg = "Redundant code: Found a statement that begins with " + std::string(valueTok->isNumber() ? "numeric" : "string") + " constant.";
|
std::string typeStr("string");
|
||||||
|
if (valueTok->isNumber())
|
||||||
|
typeStr = "numeric";
|
||||||
|
else if (valueTok->isBoolean())
|
||||||
|
typeStr = "bool";
|
||||||
|
msg = "Redundant code: Found a statement that begins with " + typeStr + " constant.";
|
||||||
|
}
|
||||||
else if (!tok)
|
else if (!tok)
|
||||||
msg = "Redundant code: Found a statement that begins with " + type + " constant.";
|
msg = "Redundant code: Found a statement that begins with " + type + " constant.";
|
||||||
else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) {
|
else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) {
|
||||||
|
|
|
@ -386,6 +386,36 @@ private:
|
||||||
|
|
||||||
check("void f(int x) { static_cast<unsigned>(x); }");
|
check("void f(int x) { static_cast<unsigned>(x); }");
|
||||||
ASSERT_EQUALS("[test.cpp:1]: (warning) Found unused cast of expression 'x'.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:1]: (warning) Found unused cast of expression 'x'.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(int x, int* p) {\n"
|
||||||
|
" static_cast<void>(x);\n"
|
||||||
|
" (void)x;\n"
|
||||||
|
" static_cast<void*>(p);\n"
|
||||||
|
" (void*)p;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() { false; }"); // #10856
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (warning) Redundant code: Found a statement that begins with bool constant.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(int i) {\n"
|
||||||
|
" (float)(char)i;\n"
|
||||||
|
" static_cast<float>((char)i);\n"
|
||||||
|
" (char)static_cast<float>(i);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (warning) Found unused cast of expression 'i'.\n"
|
||||||
|
"[test.cpp:3]: (warning) Found unused cast of expression 'i'.\n"
|
||||||
|
"[test.cpp:4]: (warning) Found unused cast of expression 'i'.\n",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
|
check("struct S; struct T; struct U;\n"
|
||||||
|
"void f() {\n"
|
||||||
|
" T t;\n"
|
||||||
|
" (S)(U)t;\n"
|
||||||
|
" (S)static_cast<U>(t);\n"
|
||||||
|
" static_cast<S>((U)t);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void vardecl() {
|
void vardecl() {
|
||||||
|
|
Loading…
Reference in New Issue