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 1/8] [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 2/8] 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 3/8] 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 4/8] 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 5/8] 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 6/8] 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 7/8] 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 8/8] 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!"); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
