[clang] [analyzer][NFC] Document and centralize the CallEvent argument/parameter index mapping (PR #221252)
Benedek Kaibas via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 14 04:05:07 PDT 2026
https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/221252
>From 636524a109f54079f6715ab5779fa06317f1fd17 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 4 Sep 2026 17:20:44 +0200
Subject: [PATCH 01/10] [analyzer][NFC] Document and centralize the CallEvent
argument/parameter index mapping
---
.../Core/PathSensitive/CallEvent.h | 29 +++++-
.../Core/PathSensitive/MemRegion.h | 7 +-
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 98 ++++++++++++-------
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 9 +-
4 files changed, 104 insertions(+), 39 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 2010e4b0da84b..5e70928b582e3 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -420,6 +420,9 @@ class CallEvent {
/// Returns memory location for a parameter variable within the callee stack
/// frame. The behavior is undefined if the block count is different from the
/// one that is there when call happens. May fail; returns null on failure.
+ ///
+ /// \param Index refers to the index of the declared parameter of the callee.
+ /// See getDeclaredParameterIndex().
const ParamVarRegion *getParameterLocation(unsigned Index,
unsigned BlockCount) const;
@@ -429,6 +432,9 @@ class CallEvent {
/// if we are supposed to construct an argument directly, we may still
/// not do that because we don't know how (i.e., construction context is
/// unavailable in the CFG or not supported by the analyzer).
+ ///
+ /// \param Index index of the argument as understood by the AST.
+ /// See getASTArgumentIndex().
bool isArgumentConstructedDirectly(unsigned Index) const {
// This assumes that the object was not yet removed from the state.
return ExprEngine::getObjectUnderConstruction(
@@ -437,9 +443,13 @@ class CallEvent {
}
/// Some calls have parameter numbering mismatched from argument numbering.
- /// This function converts an argument index to the corresponding
- /// parameter index. Returns std::nullopt is the argument doesn't correspond
+ /// This function converts an argument index as understood by the AST to the
+ /// index of the *declared* parameter of the callee that this argument
+ /// initializes. Returns std::nullopt if the argument doesn't correspond
/// to any parameter variable.
+ ///
+ /// Note that \c clang::AnyCall::arguments() uses the opposite convention:
+ /// there the object argument is part of the argument list.
virtual std::optional<unsigned>
getAdjustedParameterIndex(unsigned ASTArgumentIndex) const {
return ASTArgumentIndex;
@@ -452,6 +462,21 @@ class CallEvent {
return CallArgumentIndex;
}
+ /// Returns the declared parameter index that CallEvent argument
+ /// \p CallArgumentIndex (as understood by CallEvent) initializes or
+ /// std::nullopt if that argument does not initialize any declared parameter.
+ ///
+ /// This is the index to use with parameters() and getParameterLocation().
+ /// Note that this is not necessarily equal to \p CallArgumentIndex. For an
+ /// overloaded operator call, the object is passed as argument 0, but it is
+ /// not a declared parameter of an implicit ombject member function. For an
+ /// explicit object member function, the object is likewise passed as
+ /// argument 0, but there it is a declared parameter #0.
+ std::optional<unsigned>
+ getDeclaredParameterIndex(unsigned CallArgumentIndex) const {
+ return getAdjustedParameterIndex(getASTArgumentIndex(CallArgumentIndex));
+ }
+
/// Returns the construction context of the call, if it is a C++ constructor
/// call or a call of a function returning a C++ class instance. Otherwise
/// return nullptr.
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index c3d6d552d5e56..e5f8457555ec6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -1073,6 +1073,10 @@ class ParamVarRegion : public VarRegion {
friend class MemRegionManager;
const Expr *OriginExpr;
+
+ /// Index of teh declared parameter of the callee that this region stands
+ /// for. This is not necessarily the index of the corresponding argument
+ /// in `OriginExpr`. See `CallEvent::getDeclaredParameterIndex()`.
unsigned Index;
ParamVarRegion(const Expr *OE, unsigned Idx, const MemRegion *SReg)
@@ -1095,7 +1099,8 @@ class ParamVarRegion : public VarRegion {
QualType getValueType() const override;
- /// TODO: What does this return?
+ /// \returns the declared parameter of the callee that this region
+ /// stands for (`getStackFrame()->getDecl()->parameters()[getIndex()]`).
const ParmVarDecl *getDecl() const override;
bool canPrintPrettyAsExpr() const override;
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 2338c06d5f992..8eab3f19dc0a8 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -449,8 +449,13 @@ static SVal processArgument(SVal Value, const Expr *ArgumentExpr,
/// Or returns the cast argument if it needed a cast.
/// Or returns 'Unknown' if it would need a cast but the callsite and the
/// runtime definition don't match in terms of argument and parameter count.
-static SVal castArgToParamTypeIfNeeded(const CallEvent &Call, unsigned ArgIdx,
- SVal ArgVal, SValBuilder &SVB) {
+///
+/// \param DeclParamIdx index of the declared parameter that \p ArgExpr
+/// initializes. See CallEvent::getDeclaredParameterIndex().
+static SVal castArgToParamTypeIfNeeded(const CallEvent &Call,
+ unsigned DeclParamIdx,
+ const Expr *ArgExpr, SVal ArgVal,
+ SValBuilder &SVB) {
const auto *CallExprDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
if (!CallExprDecl)
return ArgVal;
@@ -466,52 +471,77 @@ static SVal castArgToParamTypeIfNeeded(const CallEvent &Call, unsigned ArgIdx,
return ArgVal;
// Only do this cast if the number arguments at the callsite matches with
- // the parameters at the runtime definition.
+ // the parameters at the runtime definition. Note that this point is only
+ // reached for C functions without a prototype, so the argument indices
+ // and the declared parameter indices coincide.
if (Call.getNumArgs() != Definition->getNumParams())
return UnknownVal();
- const Expr *ArgExpr = Call.getArgExpr(ArgIdx);
- const ParmVarDecl *Param = Definition->getParamDecl(ArgIdx);
+ const ParmVarDecl *Param = Definition->getParamDecl(DeclParamIdx);
return SVB.evalCast(ArgVal, Param->getType(), ArgExpr->getType());
}
+/// Binds the value of a single argument to the region of the parameter it
+/// initializes in the callee's stack frame.
+///
+/// \param ParamDecl the declared parameter initialized by this argument.
+/// \param DeclParamIdx index of \p ParamDecl among the callee's declared
+/// parameters. See CallEvent::getDeclaredParameterIndex().
+/// \param ASTArgIdx index of \p ArgExpr in the origin expression's argument
+/// list. See CallEvent::getASTArgumentIndex(). Note that this is not
+/// necessarily equal to \p DeclParamIdx.
+static void addParameterValueToBindings(const StackFrame *CalleeSF,
+ CallEvent::BindingsTy &Bindings,
+ SValBuilder &SVB, const CallEvent &Call,
+ const ParmVarDecl *ParamDecl,
+ unsigned DeclParamIdx,
+ unsigned ASTArgIdx, const Expr *ArgExpr,
+ SVal ArgVal) {
+ assert(ParamDecl && "Formal parameter has no decl?");
+
+ // TODO: Support allocator calls.
+ if (Call.getKind() != CE_CXXAllocator)
+ if (Call.isArgumentConstructedDirectly(ASTArgIdx))
+ return;
+
+ // TODO: Allocators should receive the correct size and possibly alignment,
+ // determined in compile-time but not represented as arg-expressions,
+ // which makes getArgSVal() fail and return UnknownVal.
+ if (ArgVal.isUnknown())
+ return;
+
+ // Cast the argument value to match the type of the parameter in some
+ // edge-cases.
+ ArgVal = castArgToParamTypeIfNeeded(Call, DeclParamIdx, ArgExpr, ArgVal, SVB);
+
+ Loc ParamLoc = SVB.makeLoc(SVB.getRegionManager().getParamVarRegion(
+ Call.getOriginExpr(), DeclParamIdx, CalleeSF));
+ Bindings.emplace_back(ParamLoc,
+ processArgument(ArgVal, ArgExpr, ParamDecl, SVB));
+}
+
static void addParameterValuesToBindings(const StackFrame *CalleeSF,
CallEvent::BindingsTy &Bindings,
SValBuilder &SVB,
const CallEvent &Call,
ArrayRef<ParmVarDecl *> parameters) {
- MemRegionManager &MRMgr = SVB.getRegionManager();
-
- // If the function has fewer parameters than the call has arguments, we simply
- // do not bind any values to them.
- unsigned NumArgs = Call.getNumArgs();
- unsigned Idx = 0;
- ArrayRef<ParmVarDecl*>::iterator I = parameters.begin(), E = parameters.end();
- for (; I != E && Idx < NumArgs; ++I, ++Idx) {
- assert(*I && "Formal parameter has no decl?");
-
- // TODO: Support allocator calls.
- if (Call.getKind() != CE_CXXAllocator)
- if (Call.isArgumentConstructedDirectly(Call.getASTArgumentIndex(Idx)))
- continue;
-
- // TODO: Allocators should receive the correct size and possibly alignment,
- // determined in compile-time but not represented as arg-expressions,
- // which makes getArgSVal() fail and return UnknownVal.
- SVal ArgVal = Call.getArgSVal(Idx);
- const Expr *ArgExpr = Call.getArgExpr(Idx);
-
- if (ArgVal.isUnknown())
+ for (unsigned Idx = 0, NumArgs = Call.getNumArgs(); Idx != NumArgs; ++Idx) {
+ // An argument that doesn't initialize a declared parameter, such as the
+ // object argument of an overloaded operator call.
+ std::optional<unsigned> DeclParamIdx = Call.getDeclaredParameterIndex(Idx);
+ if (!DeclParamIdx)
continue;
- // Cast the argument value to match the type of the parameter in some
- // edge-cases.
- ArgVal = castArgToParamTypeIfNeeded(Call, Idx, ArgVal, SVB);
+ // If the call has more arguments than the function has parameters, the
+ // extra ones are left unbound. Since the indices are monotonic, no later
+ // argument has a parameter either, so we can stop here.
+ if (*DeclParamIdx >= parameters.size())
+ break;
- Loc ParamLoc = SVB.makeLoc(
- MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeSF));
- Bindings.push_back(
- std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB)));
+ addParameterValueToBindings(CalleeSF, Bindings, SVB, Call,
+ parameters[*DeclParamIdx], *DeclParamIdx,
+ Call.getASTArgumentIndex(Idx),
+ Call.getArgExpr(Idx), Call.getArgSVal(Idx));
}
// FIXME: Variadic arguments are not handled at all right now.
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 9fb167ee2ea4a..52cb267304b67 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -350,8 +350,13 @@ SVal ExprEngine::computeObjectUnderConstruction(
// Operator arguments do not correspond to operator parameters
// because this-argument is implemented as a normal argument in
// operator call expressions but not in operator declarations.
- const TypedValueRegion *TVR = Caller->getParameterLocation(
- *Caller->getAdjustedParameterIndex(Idx), NumVisitedCaller);
+ std::optional<unsigned> DeclParamIdx =
+ Caller->getAdjustedParameterIndex(Idx);
+ if (!DeclParamIdx)
+ return std::nullopt;
+
+ const TypedValueRegion *TVR =
+ Caller->getParameterLocation(*DeclParamIdx, NumVisitedCaller);
if (!TVR)
return std::nullopt;
>From 25f5339a6ef0e59ac4e1e478215ac07eadcd46a4 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Wed, 9 Sep 2026 15:15:01 +0200
Subject: [PATCH 02/10] Make getParameterLocation accept
std::optional<unsigned>.
---
.../clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h | 2 +-
.../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h | 2 +-
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 7 +++++--
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 9 ++-------
4 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 5e70928b582e3..8909c87424845 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -423,7 +423,7 @@ class CallEvent {
///
/// \param Index refers to the index of the declared parameter of the callee.
/// See getDeclaredParameterIndex().
- const ParamVarRegion *getParameterLocation(unsigned Index,
+ const ParamVarRegion *getParameterLocation(std::optional<unsigned> Index,
unsigned BlockCount) const;
/// Returns true if on the current path, the argument was constructed by
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index e5f8457555ec6..5730da8c17257 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -1074,7 +1074,7 @@ class ParamVarRegion : public VarRegion {
const Expr *OriginExpr;
- /// Index of teh declared parameter of the callee that this region stands
+ /// Index of the declared parameter of the callee that this region stands
/// for. This is not necessarily the index of the corresponding argument
/// in `OriginExpr`. See `CallEvent::getDeclaredParameterIndex()`.
unsigned Index;
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 8eab3f19dc0a8..6a8bf3d571557 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -189,7 +189,10 @@ const StackFrame *CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
}
const ParamVarRegion
-*CallEvent::getParameterLocation(unsigned Index, unsigned BlockCount) const {
+*CallEvent::getParameterLocation(std::optional<unsigned> Index, unsigned BlockCount) const {
+ if (!Index)
+ return nullptr;
+
const StackFrame *SF = getCalleeStackFrame(BlockCount);
// We cannot construct a VarRegion without a stack frame.
if (!SF)
@@ -197,7 +200,7 @@ const ParamVarRegion
const ParamVarRegion *PVR =
State->getStateManager().getRegionManager().getParamVarRegion(
- getOriginExpr(), Index, SF);
+ getOriginExpr(), *Index, SF);
return PVR;
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 52cb267304b67..423b9a979ab14 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -350,13 +350,8 @@ SVal ExprEngine::computeObjectUnderConstruction(
// Operator arguments do not correspond to operator parameters
// because this-argument is implemented as a normal argument in
// operator call expressions but not in operator declarations.
- std::optional<unsigned> DeclParamIdx =
- Caller->getAdjustedParameterIndex(Idx);
- if (!DeclParamIdx)
- return std::nullopt;
-
- const TypedValueRegion *TVR =
- Caller->getParameterLocation(*DeclParamIdx, NumVisitedCaller);
+ const TypedValueRegion *TVR = Caller->getParameterLocation(
+ Caller->getAdjustedParameterIndex(Idx), NumVisitedCaller);
if (!TVR)
return std::nullopt;
>From bbb49c91a4278f77997326d1f06e929475b979b6 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Wed, 9 Sep 2026 15:26:26 +0200
Subject: [PATCH 03/10] Clang format run 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 6a8bf3d571557..5a91e659dbc9a 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -189,7 +189,8 @@ const StackFrame *CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
}
const ParamVarRegion
-*CallEvent::getParameterLocation(std::optional<unsigned> Index, unsigned BlockCount) const {
+*CallEvent::getParameterLocation(std::optional<unsigned> Index,
+ unsigned BlockCount) const {
if (!Index)
return nullptr;
>From 0e7a71bc3d7705c088faad6ac46481a1048077d5 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Wed, 9 Sep 2026 22:45:26 +0200
Subject: [PATCH 04/10] Rename parameters.
---
.../StaticAnalyzer/Core/PathSensitive/CallEvent.h | 10 +++++-----
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 6 +++---
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 8909c87424845..e6bce7137466a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -421,9 +421,9 @@ class CallEvent {
/// frame. The behavior is undefined if the block count is different from the
/// one that is there when call happens. May fail; returns null on failure.
///
- /// \param Index refers to the index of the declared parameter of the callee.
+ /// \param DeclParamIdx refers to the index of the declared parameter of the callee.
/// See getDeclaredParameterIndex().
- const ParamVarRegion *getParameterLocation(std::optional<unsigned> Index,
+ const ParamVarRegion *getParameterLocation(std::optional<unsigned> DeclParamIdx,
unsigned BlockCount) const;
/// Returns true if on the current path, the argument was constructed by
@@ -433,12 +433,12 @@ class CallEvent {
/// not do that because we don't know how (i.e., construction context is
/// unavailable in the CFG or not supported by the analyzer).
///
- /// \param Index index of the argument as understood by the AST.
+ /// \param ASTArgIdx index of the argument as understood by the AST.
/// See getASTArgumentIndex().
- bool isArgumentConstructedDirectly(unsigned Index) const {
+ bool isArgumentConstructedDirectly(unsigned ASTArgIdx) const {
// This assumes that the object was not yet removed from the state.
return ExprEngine::getObjectUnderConstruction(
- getState(), {getOriginExpr(), Index}, getStackFrame())
+ getState(), {getOriginExpr(), ASTArgIdx}, getStackFrame())
.has_value();
}
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 5a91e659dbc9a..b36dd3895c21b 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -189,9 +189,9 @@ const StackFrame *CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
}
const ParamVarRegion
-*CallEvent::getParameterLocation(std::optional<unsigned> Index,
+*CallEvent::getParameterLocation(std::optional<unsigned> DeclParamIdx,
unsigned BlockCount) const {
- if (!Index)
+ if (!DeclParamIdx)
return nullptr;
const StackFrame *SF = getCalleeStackFrame(BlockCount);
@@ -201,7 +201,7 @@ const ParamVarRegion
const ParamVarRegion *PVR =
State->getStateManager().getRegionManager().getParamVarRegion(
- getOriginExpr(), *Index, SF);
+ getOriginExpr(), *DeclParamIdx, SF);
return PVR;
}
>From 1fe60ced446e9d7b6d4eccb3a4df22265610482a Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Wed, 9 Sep 2026 23:11:55 +0200
Subject: [PATCH 05/10] Rename getAdjustedParameterIndex to
adjustASTArgIdxToDeclParamIdx.
---
.../clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h | 9 +++++----
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index e6bce7137466a..335c1b924dab6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -451,7 +451,7 @@ class CallEvent {
/// Note that \c clang::AnyCall::arguments() uses the opposite convention:
/// there the object argument is part of the argument list.
virtual std::optional<unsigned>
- getAdjustedParameterIndex(unsigned ASTArgumentIndex) const {
+ adjustASTArgIdxToDeclParamIdx(unsigned ASTArgumentIndex) const {
return ASTArgumentIndex;
}
@@ -474,7 +474,8 @@ class CallEvent {
/// argument 0, but there it is a declared parameter #0.
std::optional<unsigned>
getDeclaredParameterIndex(unsigned CallArgumentIndex) const {
- return getAdjustedParameterIndex(getASTArgumentIndex(CallArgumentIndex));
+ return adjustASTArgIdxToDeclParamIdx(
+ getASTArgumentIndex(CallArgumentIndex));
}
/// Returns the construction context of the call, if it is a C++ constructor
@@ -794,7 +795,7 @@ class CXXStaticOperatorCall : public SimpleFunctionCall {
}
std::optional<unsigned>
- getAdjustedParameterIndex(unsigned ASTArgumentIndex) const override {
+ adjustASTArgIdxToDeclParamIdx(unsigned ASTArgumentIndex) const override {
// Ignore the object parameter that is not used for static member functions.
if (ASTArgumentIndex == 0)
return std::nullopt;
@@ -900,7 +901,7 @@ class CXXMemberOperatorCall : public CXXInstanceCall {
}
std::optional<unsigned>
- getAdjustedParameterIndex(unsigned ASTArgumentIndex) const override {
+ adjustASTArgIdxToDeclParamIdx(unsigned ASTArgumentIndex) const override {
// For member operator calls argument 0 on the expression corresponds
// to implicit this-parameter on the declaration.
return (ASTArgumentIndex > 0)
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index b36dd3895c21b..560283a5697e6 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -290,7 +290,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
// currently hard to figure out.
if (getKind() != CE_CXXAllocator)
if (isArgumentConstructedDirectly(Idx))
- if (auto AdjIdx = getAdjustedParameterIndex(Idx))
+ if (auto AdjIdx = adjustASTArgIdxToDeclParamIdx(Idx))
if (const TypedValueRegion *TVR =
getParameterLocation(*AdjIdx, BlockCount))
ValuesToInvalidate.push_back(loc::MemRegionVal(TVR));
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 423b9a979ab14..6979e45e8deb9 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -351,7 +351,7 @@ SVal ExprEngine::computeObjectUnderConstruction(
// because this-argument is implemented as a normal argument in
// operator call expressions but not in operator declarations.
const TypedValueRegion *TVR = Caller->getParameterLocation(
- Caller->getAdjustedParameterIndex(Idx), NumVisitedCaller);
+ Caller->adjustASTArgIdxToDeclParamIdx(Idx), NumVisitedCaller);
if (!TVR)
return std::nullopt;
>From 275fe5569a8f94e0fb24759f5650cd62c5405514 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Thu, 10 Sep 2026 15:26:34 +0200
Subject: [PATCH 06/10] Rewrite addParameterValueToBindings to have less
parameters.
---
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 560283a5697e6..221e255f57ff4 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -491,29 +491,25 @@ static SVal castArgToParamTypeIfNeeded(const CallEvent &Call,
/// \param ParamDecl the declared parameter initialized by this argument.
/// \param DeclParamIdx index of \p ParamDecl among the callee's declared
/// parameters. See CallEvent::getDeclaredParameterIndex().
-/// \param ASTArgIdx index of \p ArgExpr in the origin expression's argument
-/// list. See CallEvent::getASTArgumentIndex(). Note that this is not
-/// necessarily equal to \p DeclParamIdx.
static void addParameterValueToBindings(const StackFrame *CalleeSF,
CallEvent::BindingsTy &Bindings,
SValBuilder &SVB, const CallEvent &Call,
const ParmVarDecl *ParamDecl,
- unsigned DeclParamIdx,
- unsigned ASTArgIdx, const Expr *ArgExpr,
- SVal ArgVal) {
+ unsigned DeclParamIdx, unsigned Idx) {
assert(ParamDecl && "Formal parameter has no decl?");
// TODO: Support allocator calls.
if (Call.getKind() != CE_CXXAllocator)
- if (Call.isArgumentConstructedDirectly(ASTArgIdx))
+ if (Call.isArgumentConstructedDirectly(Call.getASTArgumentIndex(Idx)))
return;
+ SVal ArgVal = Call.getArgSVal(Idx);
// TODO: Allocators should receive the correct size and possibly alignment,
// determined in compile-time but not represented as arg-expressions,
// which makes getArgSVal() fail and return UnknownVal.
if (ArgVal.isUnknown())
return;
-
+ const Expr *ArgExpr = Call.getArgExpr(Idx);
// Cast the argument value to match the type of the parameter in some
// edge-cases.
ArgVal = castArgToParamTypeIfNeeded(Call, DeclParamIdx, ArgExpr, ArgVal, SVB);
@@ -543,9 +539,7 @@ static void addParameterValuesToBindings(const StackFrame *CalleeSF,
break;
addParameterValueToBindings(CalleeSF, Bindings, SVB, Call,
- parameters[*DeclParamIdx], *DeclParamIdx,
- Call.getASTArgumentIndex(Idx),
- Call.getArgExpr(Idx), Call.getArgSVal(Idx));
+ parameters[*DeclParamIdx], *DeclParamIdx, Idx);
}
// FIXME: Variadic arguments are not handled at all right now.
>From 625ef876e6e0e9adca77f053fc97a4e000cdc6d9 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Thu, 10 Sep 2026 22:05:41 +0200
Subject: [PATCH 07/10] Rename Index to DeclParamIdx.
---
.../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 5730da8c17257..0caffbeadf4dc 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -1077,10 +1077,10 @@ class ParamVarRegion : public VarRegion {
/// Index of the declared parameter of the callee that this region stands
/// for. This is not necessarily the index of the corresponding argument
/// in `OriginExpr`. See `CallEvent::getDeclaredParameterIndex()`.
- unsigned Index;
+ unsigned DeclParamIdx;
ParamVarRegion(const Expr *OE, unsigned Idx, const MemRegion *SReg)
- : VarRegion(SReg, ParamVarRegionKind), OriginExpr(OE), Index(Idx) {
+ : VarRegion(SReg, ParamVarRegionKind), OriginExpr(OE), DeclParamIdx(Idx) {
assert(!cast<StackSpaceRegion>(SReg)->getStackFrame()->inTopFrame());
assert(OriginExpr);
}
@@ -1091,7 +1091,7 @@ class ParamVarRegion : public VarRegion {
public:
LLVM_ATTRIBUTE_RETURNS_NONNULL
const Expr *getOriginExpr() const { return OriginExpr; }
- unsigned getIndex() const { return Index; }
+ unsigned getIndex() const { return DeclParamIdx; }
void Profile(llvm::FoldingSetNodeID& ID) const override;
>From aa0b824ae588f238412871c1bc5a45e9d8784cb0 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Mon, 14 Sep 2026 12:37:40 +0200
Subject: [PATCH 08/10] Rename Index to DeclParamIdx.
---
clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 944601d5083e4..4b5ed79a575e4 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -208,20 +208,20 @@ QualType ParamVarRegion::getValueType() const {
const ParmVarDecl *ParamVarRegion::getDecl() const {
const Decl *D = getStackFrame()->getDecl();
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- assert(Index < FD->param_size());
- return FD->parameters()[Index];
+ assert(DeclParamIdx < FD->param_size());
+ return FD->parameters()[DeclParamIdx];
}
if (const auto *BD = dyn_cast<BlockDecl>(D)) {
- assert(Index < BD->param_size());
- return BD->parameters()[Index];
+ assert(DeclParamIdx < BD->param_size());
+ return BD->parameters()[DeclParamIdx];
}
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- assert(Index < MD->param_size());
- return MD->parameters()[Index];
+ assert(DeclParamIdx < MD->param_size());
+ return MD->parameters()[DeclParamIdx];
}
if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
- assert(Index < CD->param_size());
- return CD->parameters()[Index];
+ assert(DeclParamIdx < CD->param_size());
+ return CD->parameters()[DeclParamIdx];
}
llvm_unreachable("Unexpected Decl kind!");
}
>From 0d2974b7a15974f2db59efe96cdabb99a7cce8d9 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Mon, 14 Sep 2026 12:46:49 +0200
Subject: [PATCH 09/10] Run clang-format to fix formatting issue.
---
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 221e255f57ff4..fd8ffd2a4db3d 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -188,9 +188,9 @@ const StackFrame *CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
return ADC->getStackFrame(SF, nullptr, E, B, BlockCount, Idx);
}
-const ParamVarRegion
-*CallEvent::getParameterLocation(std::optional<unsigned> DeclParamIdx,
- unsigned BlockCount) const {
+const ParamVarRegion *
+CallEvent::getParameterLocation(std::optional<unsigned> DeclParamIdx,
+ unsigned BlockCount) const {
if (!DeclParamIdx)
return nullptr;
>From 28085c40e119d79c5d36a33d903918c120523d9e Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Mon, 14 Sep 2026 13:04:38 +0200
Subject: [PATCH 10/10] Apply formatting changes to the CallEvent header.
---
.../clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 335c1b924dab6..87e8319c6cbdf 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -421,10 +421,11 @@ class CallEvent {
/// frame. The behavior is undefined if the block count is different from the
/// one that is there when call happens. May fail; returns null on failure.
///
- /// \param DeclParamIdx refers to the index of the declared parameter of the callee.
- /// See getDeclaredParameterIndex().
- const ParamVarRegion *getParameterLocation(std::optional<unsigned> DeclParamIdx,
- unsigned BlockCount) const;
+ /// \param DeclParamIdx refers to the index of the declared parameter of the
+ /// callee. See getDeclaredParameterIndex().
+ const ParamVarRegion *
+ getParameterLocation(std::optional<unsigned> DeclParamIdx,
+ unsigned BlockCount) const;
/// Returns true if on the current path, the argument was constructed by
/// calling a C++ constructor over it. This is an internal detail of the
More information about the cfe-commits
mailing list