From b4587ff102c5c16d16f2504f4314bfae7bd11b1c Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 27 Sep 2025 20:41:05 +0200 Subject: [PATCH 1/4] Fix #14161 FN constVariablePointer (assignment to const pointer) --- lib/astutils.cpp | 5 ++++- lib/checkother.cpp | 9 +++++++-- test/testother.cpp | 10 ++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 30f10794855..bb93de01969 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2916,7 +2916,10 @@ static bool isExpressionChangedAt(const F& getExprTok, aliased = isAliasOf(tok, expr, &i); if (!aliased) return false; - if (isVariableChanged(tok, indirect + i, settings, depth)) + i += indirect; + if (tok->valueType() && tok->valueType()->pointer) + i = std::min(i, tok->valueType()->pointer); + if (isVariableChanged(tok, i, settings, depth)) return true; // TODO: Try to traverse the lambda function if (Token::Match(tok, "%var% (")) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 7a06f66f644..1b1d6194559 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1916,8 +1916,13 @@ void CheckOther::checkConstPointer() continue; if (Token::simpleMatch(parent, "(") && Token::Match(parent->astOperand1(), "if|while")) continue; - if (Token::simpleMatch(parent, "=") && parent->astOperand1() == tok) - continue; + if (Token::simpleMatch(parent, "=")) { + const Token* lhs = parent->astOperand1(); + if (lhs == tok) + continue; + if (lhs && lhs->valueType() && lhs->valueType()->isConst(vt->pointer)) + continue; + } if (const Token* ftok = getTokenArgumentFunction(tok, argn)) { if (ftok->function()) { const bool isCastArg = parent->isCast() && !ftok->function()->getOverloadedFunctions().empty(); // assume that cast changes the called function diff --git a/test/testother.cpp b/test/testother.cpp index 64e8ddf5960..18d6e54e5f5 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4497,6 +4497,16 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:2:18]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:5:18]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct T;\n" + "void use(const T*);\n" + "void f(T* tok0) {\n" + " T *tok1 = tok0;\n" + " const T *tok2 = tok1;\n" + " use(tok2);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:8]: (style) Variable 'tok1' can be declared as pointer to const [constVariablePointer]\n", + errout_str()); } void constArray() { From e26e045fea74ba4437f00e61e15e8c9d0c754bcb Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 27 Sep 2025 22:27:39 +0200 Subject: [PATCH 2/4] const --- lib/symboldatabase.cpp | 4 ++-- lib/tokenize.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 55145f1207c..04b87f050f3 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2296,7 +2296,7 @@ Variable& Variable::operator=(const Variable &var) & if (this == &var) return *this; - ValueType* vt = nullptr; + const ValueType* vt = nullptr; if (var.mValueType) vt = new ValueType(*var.mValueType); @@ -2462,7 +2462,7 @@ void Variable::setValueType(const ValueType &valueType) if (declType && !declType->next()->valueType()) return; } - auto* vt = new ValueType(valueType); + const auto* vt = new ValueType(valueType); delete mValueType; mValueType = vt; if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )"))) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9c6db66a4c6..b87c6d11103 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1243,7 +1243,7 @@ void Tokenizer::simplifyTypedefCpp() bool refToArray = false; bool ptrMember = false; bool typeOf = false; - Token *namespaceStart = nullptr; + const Token *namespaceStart = nullptr; Token *namespaceEnd = nullptr; // check for invalid input @@ -3025,7 +3025,7 @@ bool Tokenizer::simplifyUsing() ScopeInfo3 scopeInfo1; ScopeInfo3 *currentScope1 = &scopeInfo1; Token *startToken = list.front(); - Token *endToken = nullptr; + const Token *endToken = nullptr; bool inMemberFunc = false; const ScopeInfo3 * memberFuncScope = nullptr; const Token * memberFuncEnd = nullptr; @@ -3039,7 +3039,7 @@ bool Tokenizer::simplifyUsing() if (!currentScope1) return substitute; // something bad happened startToken = usingEnd->next(); - endToken = const_cast(currentScope->bodyEnd->next()); + endToken = currentScope->bodyEnd->next(); if (currentScope->type == ScopeInfo3::MemberFunction) { const ScopeInfo3 * temp = currentScope->findScope(currentScope->fullName); if (temp) { From 5de6520705f749a788c65f83253594c2038c75e9 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 27 Sep 2025 22:39:55 +0200 Subject: [PATCH 3/4] Fix --- lib/astutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index bb93de01969..b7bd4081cce 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2906,7 +2906,7 @@ static bool isExpressionChangedAt(const F& getExprTok, // TODO: Is global variable really changed by function call? return true; } - int i = 1; + nonneg int i = 1; bool aliased = false; // If we can't find the expression then assume it is an alias auto expr = getExprTok(); From 5bdd9bee9279a8ed8bf5c8da6e440bde25980f70 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 27 Sep 2025 22:59:16 +0200 Subject: [PATCH 4/4] Fix --- lib/astutils.cpp | 2 +- lib/astutils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index b7bd4081cce..33608df6fc6 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1062,7 +1062,7 @@ bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive) return false; } -bool isAliasOf(const Token* tok, const Token* expr, int* indirect) +bool isAliasOf(const Token* tok, const Token* expr, nonneg int* indirect) { const Token* r = nullptr; if (indirect) diff --git a/lib/astutils.h b/lib/astutils.h index f7a245c0430..895748acf72 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -379,7 +379,7 @@ bool isExpressionChangedAt(const Token* expr, /// If token is an alias if another variable bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr); -bool isAliasOf(const Token* tok, const Token* expr, int* indirect = nullptr); +bool isAliasOf(const Token* tok, const Token* expr, nonneg int* indirect = nullptr); const Token* getArgumentStart(const Token* ftok);