[llvm-branch-commits] [clang] [analyzer][NFC] Index parameter lookups by argument position (PR #221977)
Benedek Kaibas via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Sep 11 07:00:23 PDT 2026
https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/221977
>From b864364327448505a9d2911de02cb3f55c72fe06 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Mon, 7 Sep 2026 15:22:38 +0200
Subject: [PATCH 1/4] [analyzer] Replace getAdjustedParameterIndex with
getDeclaredParameterIndex in CallEvent.cpp
---
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 8eab3f19dc0a8..cbcc0c7d3b717 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -285,10 +285,10 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
// TODO: This is unnecessary when there's no destructor, but that's
// currently hard to figure out.
if (getKind() != CE_CXXAllocator)
- if (isArgumentConstructedDirectly(Idx))
- if (auto AdjIdx = getAdjustedParameterIndex(Idx))
+ if (isArgumentConstructedDirectly(getASTArgumentIndex(Idx)))
+ if (std::optional<unsigned> DeclParamIdx = getDeclaredParameterIndex(Idx))
if (const TypedValueRegion *TVR =
- getParameterLocation(*AdjIdx, BlockCount))
+ getParameterLocation(*DeclParamIdx, BlockCount))
ValuesToInvalidate.push_back(loc::MemRegionVal(TVR));
}
>From 7c0f02d11535ceeba342e2328d4d432b5afdd50e Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Mon, 7 Sep 2026 15:36:43 +0200
Subject: [PATCH 2/4] Run clang-format once again.
---
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index cbcc0c7d3b717..4eed56b2963b5 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -286,7 +286,8 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
// currently hard to figure out.
if (getKind() != CE_CXXAllocator)
if (isArgumentConstructedDirectly(getASTArgumentIndex(Idx)))
- if (std::optional<unsigned> DeclParamIdx = getDeclaredParameterIndex(Idx))
+ if (std::optional<unsigned> DeclParamIdx =
+ getDeclaredParameterIndex(Idx))
if (const TypedValueRegion *TVR =
getParameterLocation(*DeclParamIdx, BlockCount))
ValuesToInvalidate.push_back(loc::MemRegionVal(TVR));
>From 3aa448a5e8cd832072cbeb0edfec6f24b2edf922 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Tue, 8 Sep 2026 14:18:45 +0200
Subject: [PATCH 3/4] [analyzer][NFC] Index parameter lookups by argument
position
---
.../Checkers/CallAndMessageChecker.cpp | 9 +++---
.../Checkers/NonNullParamChecker.cpp | 31 ++++++++++++++++---
.../Checkers/SmartPtrModeling.cpp | 4 +++
3 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 3997da0ba5dc5..b9fbc32d50ff9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -577,14 +577,13 @@ ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
const BugType &BT = isa<ObjCMethodCall>(Call) ? MsgArgBug : CallArgBug;
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
+ ArrayRef<ParmVarDecl *> Params = Call.parameters();
for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
- const ParmVarDecl *ParamDecl = nullptr;
- if (FD && i < FD->getNumParams())
- ParamDecl = FD->getParamDecl(i);
+ // For variadic functions a corresponding parameter decl might not exist.
+ const ParmVarDecl *PVD = i < Params.size() ? Params[i] : nullptr;
if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
Call.getArgExpr(i), i, checkUninitFields, Call, BT,
- ParamDecl))
+ PVD))
return nullptr;
}
return State;
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index 2cc633fa5649f..27f393cbb5489 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -46,10 +46,27 @@ class NonNullParamChecker
const Expr *ArgE) const;
};
+/// The bit vectors below are indexed by \p Call's own argument numbering
+/// and not by the declared parameter index. The two differ for an
+/// explicit object parameter. The explicit object parameter is declared
+/// as #0, but \p Call does not count the object as one of its arguments.
+///
+/// \returns how many leading declared parameters \p Call has no argument
+/// for.
+template <class CallType>
+unsigned getDeclParameterOffset(const CallType &Call) {
+ if (const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(Call.getDecl())) {
+ assert(FD->getNumParams() >= Call.parameters().size());
+ return FD->getNumParams() - Call.parameters().size();
+ }
+ return 0;
+}
+
template <class CallType>
void setBitsAccordingToFunctionAttributes(const CallType &Call,
llvm::SmallBitVector &AttrNonNull) {
const Decl *FD = Call.getDecl();
+ const unsigned Offset = getDeclParameterOffset(Call);
for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
if (!NonNull->args_size()) {
@@ -63,9 +80,12 @@ void setBitsAccordingToFunctionAttributes(const CallType &Call,
// 'nonnull' attribute's parameters are 1-based and should be adjusted to
// match actual AST parameter/argument indices.
unsigned IdxAST = Idx.getASTIndex();
- if (IdxAST >= AttrNonNull.size())
+ if (IdxAST < Offset)
+ continue;
+ const unsigned IdxArg = IdxAST - Offset;
+ if (IdxArg >= AttrNonNull.size())
continue;
- AttrNonNull.set(IdxAST);
+ AttrNonNull.set(IdxArg);
}
}
}
@@ -73,13 +93,14 @@ void setBitsAccordingToFunctionAttributes(const CallType &Call,
template <class CallType>
void setBitsAccordingToParameterAttributes(const CallType &Call,
llvm::SmallBitVector &AttrNonNull) {
+ unsigned ArgIdx = 0;
for (const ParmVarDecl *Parameter : Call.parameters()) {
- unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
- if (ParameterIndex == AttrNonNull.size())
+ if (ArgIdx == AttrNonNull.size())
break;
if (Parameter->hasAttr<NonNullAttr>())
- AttrNonNull.set(ParameterIndex);
+ AttrNonNull.set(ArgIdx);
+ ++ArgIdx;
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index ad81e5076f931..cf5ef57a07b26 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -837,6 +837,10 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
const MemRegion *ThisRegion =
cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
+ // `getCXXThisVal` does not model explicit object parameters and
+ // in case of an explicit object parameter it can be null.
+ if (!ThisRegion)
+ return;
QualType ThisType = cast<CXXMethodDecl>(Call.getDecl())->getThisType();
SVal InnerPointerVal;
>From d957c72209b2e827e3cbbc917f249e3bb72c3e69 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 11 Sep 2026 15:59:40 +0200
Subject: [PATCH 4/4] Add comment for indexes and FIXME.
---
.../Checkers/CallAndMessageChecker.cpp | 21 ++++++++++++++-----
.../Checkers/SmartPtrModeling.cpp | 2 ++
2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index b9fbc32d50ff9..8c98ec256b03c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -578,12 +578,23 @@ ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
const BugType &BT = isa<ObjCMethodCall>(Call) ? MsgArgBug : CallArgBug;
ArrayRef<ParmVarDecl *> Params = Call.parameters();
- for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
+ // CallEvent uses three index spaces. ASTArgIdx indexes the AST argument list
+ // (CallExpr::getArg()). DeclParamIdx indexes the callee's declared parameters
+ // (FunctionDecl::getParamDecl()). NativeIdx indexes the arguments exposed by
+ // CallEvent through getArgExpr() and is bounded by getNumArgs().
+ //
+ // FIXME: CallEvent does not yet treat an explicit object parameter as an
+ // object the way it does for implicit `this`, so it stays a regular argument.
+ // Indexing still lines up today only by coincidence, because parameters()
+ // includes it too.
+ for (unsigned NativeIdx = 0, e = Call.getNumArgs(); NativeIdx != e; ++NativeIdx) {
// For variadic functions a corresponding parameter decl might not exist.
- const ParmVarDecl *PVD = i < Params.size() ? Params[i] : nullptr;
- if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
- Call.getArgExpr(i), i, checkUninitFields, Call, BT,
- PVD))
+ const ParmVarDecl *PVD =
+ NativeIdx < Params.size() ? Params[NativeIdx] : nullptr;
+ if (PreVisitProcessArg(C, Call.getArgSVal(NativeIdx),
+ Call.getArgSourceRange(NativeIdx),
+ Call.getArgExpr(NativeIdx), NativeIdx,
+ checkUninitFields, Call, BT, PVD))
return nullptr;
}
return State;
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index cf5ef57a07b26..fde0153220b89 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -839,6 +839,8 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
// `getCXXThisVal` does not model explicit object parameters and
// in case of an explicit object parameter it can be null.
+ // TODO: Instead of the early return the checker should support
+ // explicit object parameters.
if (!ThisRegion)
return;
QualType ThisType = cast<CXXMethodDecl>(Call.getDecl())->getThisType();
More information about the llvm-branch-commits
mailing list