From 2ba733a3d0b3e8dbae66c647267e4ac7eb75cbdd Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 16 Sep 2025 17:28:12 -0500 Subject: [PATCH 1/2] Fix 14136: False positive: constParameterReference when using void cast --- lib/astutils.cpp | 5 +++++ lib/astutils.h | 2 ++ lib/checkother.cpp | 17 +++++++++++++++++ lib/checkuninitvar.cpp | 5 ----- test/testother.cpp | 7 +++++-- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 30f10794855..9a9bdbfa8b1 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -429,6 +429,11 @@ bool isStlStringType(const Token* tok) (Token::simpleMatch(tok, "std :: basic_string <") && !Token::simpleMatch(tok->linkAt(3), "> ::")); } +bool isVoidCast(const Token *tok) +{ + return Token::simpleMatch(tok, "(") && tok->isCast() && tok->valueType() && tok->valueType()->type == ValueType::Type::VOID && tok->valueType()->pointer == 0; +} + bool isTemporary(const Token* tok, const Library* library, bool unknown) { if (!tok) diff --git a/lib/astutils.h b/lib/astutils.h index f7a245c0430..2281b35cfbd 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -188,6 +188,8 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp, bool isVariableDecl(const Token* tok); bool isStlStringType(const Token* tok); +bool isVoidCast(const Token *tok); + bool isTemporary(const Token* tok, const Library* library, bool unknown = false); const Token* previousBeforeAstLeftmostLeaf(const Token* tok); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 7a06f66f644..7103beafeb6 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1641,6 +1641,21 @@ static bool isVariableMutableInInitializer(const Token* start, const Token * end return false; } +static bool isCastToVoid(const Variable* var) +{ + if(!var) + return false; + if(!var->scope()) + return false; + for (const Token *tok = var->scope()->bodyStart; tok != var->scope()->bodyEnd; tok = tok->next()) { + if(tok->varId() != var->declarationId()) + continue; + if(isVoidCast(tok->astParent())) + return true; + } + return false; +} + void CheckOther::checkConstVariable() { if ((!mSettings->severity.isEnabled(Severity::style) || mTokenizer->isC()) && !mSettings->isPremiumEnabled("constVariable")) @@ -1689,6 +1704,8 @@ void CheckOther::checkConstVariable() continue; if (isStructuredBindingVariable(var)) // TODO: check all bound variables continue; + if (isCastToVoid(var)) + continue; if (isVariableChanged(var, *mSettings)) continue; const bool hasFunction = function != nullptr; diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index d0217f9c075..4c72a7a0a9b 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1150,11 +1150,6 @@ static bool astIsRhs(const Token *tok) return tok && tok->astParent() && tok == tok->astParent()->astOperand2(); } -static bool isVoidCast(const Token *tok) -{ - return Token::simpleMatch(tok, "(") && tok->isCast() && tok->valueType() && tok->valueType()->type == ValueType::Type::VOID && tok->valueType()->pointer == 0; -} - const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect) { const bool cpp = vartok->isCpp(); diff --git a/test/testother.cpp b/test/testother.cpp index a0583ec13df..d40c8298ee7 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -3300,6 +3300,10 @@ class TestOther : public TestFixture { "};\n"); ASSERT_EQUALS("", errout_str()); + // #14136 + check("void f(int& x) { (void)x; }\n"); + ASSERT_EQUALS("", errout_str()); + check("void e();\n" "void g(void);\n" "void h(void);\n" @@ -12160,8 +12164,7 @@ class TestOther : public TestFixture { " for (auto &j : g(std::move(l))) { (void)j; }\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4:20]: (style) Variable 'j' can be declared as reference to const [constVariableReference]\n" - "[test.cpp:4:36]: (warning) Access of moved variable 'l'. [accessMoved]\n", + ASSERT_EQUALS("[test.cpp:4:36]: (warning) Access of moved variable 'l'. [accessMoved]\n", errout_str()); } From 37e6b81d56f59e1e4e266df635e84e0ffad9c2b0 Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 16 Sep 2025 17:29:35 -0500 Subject: [PATCH 2/2] Format --- lib/astutils.cpp | 5 +++-- lib/astutils.h | 2 +- lib/checkother.cpp | 10 +++++----- test/testother.cpp | 3 +-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 9a9bdbfa8b1..d276ade9754 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -429,9 +429,10 @@ bool isStlStringType(const Token* tok) (Token::simpleMatch(tok, "std :: basic_string <") && !Token::simpleMatch(tok->linkAt(3), "> ::")); } -bool isVoidCast(const Token *tok) +bool isVoidCast(const Token* tok) { - return Token::simpleMatch(tok, "(") && tok->isCast() && tok->valueType() && tok->valueType()->type == ValueType::Type::VOID && tok->valueType()->pointer == 0; + return Token::simpleMatch(tok, "(") && tok->isCast() && tok->valueType() && + tok->valueType()->type == ValueType::Type::VOID && tok->valueType()->pointer == 0; } bool isTemporary(const Token* tok, const Library* library, bool unknown) diff --git a/lib/astutils.h b/lib/astutils.h index 2281b35cfbd..1ec6a39bb1d 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -188,7 +188,7 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp, bool isVariableDecl(const Token* tok); bool isStlStringType(const Token* tok); -bool isVoidCast(const Token *tok); +bool isVoidCast(const Token* tok); bool isTemporary(const Token* tok, const Library* library, bool unknown = false); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 7103beafeb6..d876256f034 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1643,14 +1643,14 @@ static bool isVariableMutableInInitializer(const Token* start, const Token * end static bool isCastToVoid(const Variable* var) { - if(!var) + if (!var) return false; - if(!var->scope()) + if (!var->scope()) return false; - for (const Token *tok = var->scope()->bodyStart; tok != var->scope()->bodyEnd; tok = tok->next()) { - if(tok->varId() != var->declarationId()) + for (const Token* tok = var->scope()->bodyStart; tok != var->scope()->bodyEnd; tok = tok->next()) { + if (tok->varId() != var->declarationId()) continue; - if(isVoidCast(tok->astParent())) + if (isVoidCast(tok->astParent())) return true; } return false; diff --git a/test/testother.cpp b/test/testother.cpp index d40c8298ee7..cf834566646 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -12164,8 +12164,7 @@ class TestOther : public TestFixture { " for (auto &j : g(std::move(l))) { (void)j; }\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4:36]: (warning) Access of moved variable 'l'. [accessMoved]\n", - errout_str()); + ASSERT_EQUALS("[test.cpp:4:36]: (warning) Access of moved variable 'l'. [accessMoved]\n", errout_str()); } void moveCallback()