Author: Ryosuke Niwa Date: 2026-10-11T08:10:52-07:00 New Revision: 6ebe7cb47c71fb8f96dc9db7bd9a5cc213ed88bb
URL: https://github.com/llvm/llvm-project/commit/6ebe7cb47c71fb8f96dc9db7bd9a5cc213ed88bb DIFF: https://github.com/llvm/llvm-project/commit/6ebe7cb47c71fb8f96dc9db7bd9a5cc213ed88bb.diff LOG: [alpha.webkit.UncountedLocalVarsChecker] Don't treat a const operator call on a guardian as a mutation (#230900) GuardianVisitor treated `guardian->method()` as a mutation of the guardian because the implicit object argument of a member operator call had no corresponding parameter, and the check fell back to the non-const type of the guardian itself. Skip the implicit object argument when the operator is a const member function, and only apply the argument offset for implicit object member operators so that arguments of non-member operators map to the right parameters. Also treat passing a guardian to a const reference parameter as non-mutating by checking the constness of the referenced type instead of the reference type. Coded with Claude code. Added: Modified: clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp Removed: ################################################################################ diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp index 6ba7e95b23df4..51511197072b5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp @@ -96,14 +96,22 @@ struct GuardianVisitor : DynamicRecursiveASTVisitor { if (isGetterOfSafePtr(Method).value_or(false)) return true; } + // For a member operator call, the first argument is the implicit object. + auto *OperatorMethod = dyn_cast<CXXMethodDecl>(Callee); + if (!isa<CXXOperatorCallExpr>(CE) || !OperatorMethod || + !OperatorMethod->isImplicitObjectMemberFunction()) + OperatorMethod = nullptr; unsigned ArgIndex = 0; - unsigned ArgOffset = isa<CXXOperatorCallExpr>(CE); + unsigned ArgOffset = OperatorMethod ? 1 : 0; for (auto *Arg : CE->arguments()) { ParmVarDecl *Parm = nullptr; if (ArgIndex >= ArgOffset) { unsigned ParmIndex = ArgIndex - ArgOffset; if (ParmIndex < Callee->getNumParams()) Parm = Callee->getParamDecl(ParmIndex); + } else if (OperatorMethod->isConst()) { + ArgIndex++; + continue; } if (mutatesGuardian(Arg, Parm)) return false; @@ -152,7 +160,7 @@ struct GuardianVisitor : DynamicRecursiveASTVisitor { return false; return !ArgType.getNonReferenceType().isConstQualified(); } - return !ArgType.isConstQualified(); + return !ArgType.getNonReferenceType().isConstQualified(); } }; diff --git a/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp index a0ce0ffbff90d..a3f7d23328e52 100644 --- a/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp +++ b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp @@ -360,6 +360,15 @@ void local_var_with_guardian_checked_ref() { } } +void local_var_with_guardian_used_via_arrow() { + Ref<RefCountableAndCheckable> a = *provide_obj(); + { + RefCountableAndCheckable* b = a.ptr(); + a->method(); + b->method(); + } +} + void static_var() { static RefCountableAndCheckable* a = nullptr; // expected-warning@-1{{Static local variable 'a' is a raw pointer to CheckedPtr-capable type 'RefCountableAndCheckable' [alpha.webkit.UncheckedLocalVarsChecker]}} diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp index 6c1299998e646..923bcca5c898e 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp @@ -214,6 +214,28 @@ void foo9(RefCountable& o) { } } +bool operator==(const Ref<RefCountable>&, const Ref<RefCountable>&); +void consumeConstRef(const Ref<RefCountable>&); + +void guardian_const_operator_call(RefCountable& o, Ref<RefCountable>& other) { + Ref<RefCountable> guardian(o); + { + RefCountable *bar = guardian.ptr(); + guardian->method(); + bar->method(); + } + { + RefCountable *bar = guardian.ptr(); + if (guardian == other) + bar->method(); + } + { + RefCountable *bar = guardian.ptr(); + consumeConstRef(guardian); + bar->method(); + } +} + RefCountable* provide(); struct Derived : public RefCountable { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
