https://github.com/benedekaibas updated 
https://github.com/llvm/llvm-project/pull/221252

>From 636524a109f54079f6715ab5779fa06317f1fd17 Mon Sep 17 00:00:00 2001
From: benedekaibas <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to