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