Skip to content

Commit 73de813

Browse files
#13794 FN constStatement for missing function calls (danmar#7482)
Co-authored-by: chrchr-github <noreply@github.com>
1 parent 514a8ea commit 73de813

File tree

2 files changed

+48
-15
lines changed

2 files changed

+48
-15
lines changed

lib/checkother.cpp

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,7 +2022,7 @@ static bool isConstant(const Token* tok) {
20222022
return tok && (tok->isEnumerator() || Token::Match(tok, "%bool%|%num%|%str%|%char%|nullptr|NULL"));
20232023
}
20242024

2025-
static bool isConstStatement(const Token *tok, bool isNestedBracket = false)
2025+
static bool isConstStatement(const Token *tok, const Library& library, bool isNestedBracket = false)
20262026
{
20272027
if (!tok)
20282028
return false;
@@ -2044,45 +2044,60 @@ static bool isConstStatement(const Token *tok, bool isNestedBracket = false)
20442044
tok2 = tok2->astParent();
20452045
}
20462046
if (Token::Match(tok, "&&|%oror%"))
2047-
return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2());
2047+
return isConstStatement(tok->astOperand1(), library) && isConstStatement(tok->astOperand2(), library);
20482048
if (Token::Match(tok, "!|~|%cop%") && (tok->astOperand1() || tok->astOperand2()))
20492049
return true;
20502050
if (Token::simpleMatch(tok->previous(), "sizeof ("))
20512051
return true;
20522052
if (isCPPCast(tok)) {
20532053
if (Token::simpleMatch(tok->astOperand1(), "dynamic_cast") && Token::simpleMatch(tok->astOperand1()->linkAt(1)->previous(), "& >"))
20542054
return false;
2055-
return isWithoutSideEffects(tok) && isConstStatement(tok->astOperand2());
2055+
return isWithoutSideEffects(tok) && isConstStatement(tok->astOperand2(), library);
20562056
}
20572057
if (tok->isCast() && tok->next() && tok->next()->isStandardType())
2058-
return isWithoutSideEffects(tok->astOperand1()) && isConstStatement(tok->astOperand1());
2058+
return isWithoutSideEffects(tok->astOperand1()) && isConstStatement(tok->astOperand1(), library);
20592059
if (Token::simpleMatch(tok, "."))
2060-
return isConstStatement(tok->astOperand2());
2060+
return isConstStatement(tok->astOperand2(), library);
20612061
if (Token::simpleMatch(tok, ",")) {
20622062
if (tok->astParent()) // warn about const statement on rhs at the top level
2063-
return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2());
2063+
return isConstStatement(tok->astOperand1(), library) && isConstStatement(tok->astOperand2(), library);
20642064

20652065
const Token* lml = previousBeforeAstLeftmostLeaf(tok); // don't warn about matrix/vector assignment (e.g. Eigen)
20662066
if (lml)
20672067
lml = lml->next();
20682068
const Token* stream = lml;
20692069
while (stream && Token::Match(stream->astParent(), ".|[|(|*"))
20702070
stream = stream->astParent();
2071-
return (!stream || !isLikelyStream(stream)) && isConstStatement(tok->astOperand2());
2071+
return (!stream || !isLikelyStream(stream)) && isConstStatement(tok->astOperand2(), library);
20722072
}
20732073
if (Token::simpleMatch(tok, "?") && Token::simpleMatch(tok->astOperand2(), ":")) // ternary operator
2074-
return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand2());
2074+
return isConstStatement(tok->astOperand1(), library) && isConstStatement(tok->astOperand2()->astOperand1(), library) && isConstStatement(tok->astOperand2()->astOperand2(), library);
20752075
if (isBracketAccess(tok) && isWithoutSideEffects(tok->astOperand1(), /*checkArrayAccess*/ true, /*checkReference*/ false)) {
20762076
const bool isChained = succeeds(tok->astParent(), tok);
20772077
if (Token::simpleMatch(tok->astParent(), "[")) {
20782078
if (isChained)
2079-
return isConstStatement(tok->astOperand2()) && isConstStatement(tok->astParent());
2080-
return isNestedBracket && isConstStatement(tok->astOperand2());
2079+
return isConstStatement(tok->astOperand2(), library) && isConstStatement(tok->astParent(), library);
2080+
return isNestedBracket && isConstStatement(tok->astOperand2(), library);
20812081
}
2082-
return isConstStatement(tok->astOperand2(), /*isNestedBracket*/ !isChained);
2082+
return isConstStatement(tok->astOperand2(), library, /*isNestedBracket*/ !isChained);
20832083
}
20842084
if (!tok->astParent() && findLambdaEndToken(tok))
20852085
return true;
2086+
2087+
tok2 = tok;
2088+
if (tok2->str() == "::")
2089+
tok2 = tok2->next();
2090+
if (Token::Match(tok2, "%name% ;")) {
2091+
if (tok2->function())
2092+
return true;
2093+
std::string funcStr = tok2->str();
2094+
while (tok2->index() > 1 && Token::Match(tok2->tokAt(-2), "%name% ::")) {
2095+
funcStr.insert(0, tok2->strAt(-2) + "::");
2096+
tok2 = tok2->tokAt(-2);
2097+
}
2098+
if (library.functions().count(funcStr) > 0)
2099+
return true;
2100+
}
20862101
return false;
20872102
}
20882103

@@ -2174,7 +2189,7 @@ void CheckOther::checkIncompleteStatement()
21742189
// Skip statement expressions
21752190
if (Token::simpleMatch(rtok, "; } )"))
21762191
continue;
2177-
if (!isConstStatement(tok))
2192+
if (!isConstStatement(tok, mSettings->library))
21782193
continue;
21792194
if (isVoidStmt(tok))
21802195
continue;
@@ -2228,6 +2243,8 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type,
22282243
msg = "Redundant code: Found unused array access.";
22292244
else if (tok->str() == "[" && !tok->astParent())
22302245
msg = "Redundant code: Found unused lambda.";
2246+
else if (Token::Match(tok, "%name%|::"))
2247+
msg = "Redundant code: Found unused function.";
22312248
else if (mSettings->debugwarnings) {
22322249
reportError(tok, Severity::debug, "debug", "constStatementError not handled.");
22332250
return;
@@ -2365,7 +2382,7 @@ void CheckOther::checkMisusedScopedObject()
23652382
if (Token::simpleMatch(parTok, "<") && parTok->link())
23662383
parTok = parTok->link()->next();
23672384
if (const Token* arg = parTok->astOperand2()) {
2368-
if (!isConstStatement(arg))
2385+
if (!isConstStatement(arg, mSettings->library))
23692386
continue;
23702387
if (parTok->str() == "(") {
23712388
if (arg->varId() && !(arg->variable() && arg->variable()->nameToken() != arg))
@@ -2826,7 +2843,7 @@ void CheckOther::checkDuplicateExpression()
28262843
} else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") {
28272844
if (!tok->astOperand1()->values().empty() && !tok->astOperand2()->values().empty() && isEqualKnownValue(tok->astOperand1(), tok->astOperand2()) &&
28282845
!isVariableChanged(tok->astParent(), /*indirect*/ 0, *mSettings) &&
2829-
isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2()))
2846+
isConstStatement(tok->astOperand1(), mSettings->library) && isConstStatement(tok->astOperand2(), mSettings->library))
28302847
duplicateValueTernaryError(tok);
28312848
else if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), *mSettings, false, true, &errorPath))
28322849
duplicateExpressionTernaryError(tok, std::move(errorPath));

test/testincompletestatement.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class TestIncompleteStatement : public TestFixture {
3030
TestIncompleteStatement() : TestFixture("TestIncompleteStatement") {}
3131

3232
private:
33-
const Settings settings = settingsBuilder().severity(Severity::warning).build();
33+
const Settings settings = settingsBuilder().severity(Severity::warning).library("std.cfg").build();
3434

3535
struct CheckOptions
3636
{
@@ -84,6 +84,7 @@ class TestIncompleteStatement : public TestFixture {
8484
TEST_CASE(archive); // ar & x
8585
TEST_CASE(ast);
8686
TEST_CASE(oror); // dostuff() || x=32;
87+
TEST_CASE(functioncall);
8788
}
8889

8990
void test1() {
@@ -792,6 +793,21 @@ class TestIncompleteStatement : public TestFixture {
792793
"}\n", dinit(CheckOptions, $.inconclusive = true));
793794
ASSERT_EQUALS("", errout_str());
794795
}
796+
797+
void functioncall() {
798+
check("void g();\n" // #13794
799+
"void f() {\n"
800+
" g;\n"
801+
" exit;\n"
802+
" std::free;\n"
803+
" ::std::terminate;\n"
804+
"}\n", dinit(CheckOptions, $.inconclusive = true));
805+
ASSERT_EQUALS("[test.cpp:3:5]: (warning) Redundant code: Found unused function. [constStatement]\n"
806+
"[test.cpp:4:5]: (warning) Redundant code: Found unused function. [constStatement]\n"
807+
"[test.cpp:5:8]: (warning) Redundant code: Found unused function. [constStatement]\n"
808+
"[test.cpp:6:10]: (warning) Redundant code: Found unused function. [constStatement]\n",
809+
errout_str());
810+
}
795811
};
796812

797813
REGISTER_TEST(TestIncompleteStatement)

0 commit comments

Comments
 (0)