llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-static-analyzer-1 @llvm/pr-subscribers-clang Author: Ryosuke Niwa (rniwa) <details> <summary>Changes</summary> Skip the analysis of Ref, RefPtr, and their variant classes in UncountedCallArgsChecker since these classes are "trusted" to not do anything dangerous. --- Full diff: https://github.com/llvm/llvm-project/pull/90153.diff 4 Files Affected: - (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+3) - (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp (+6) - (modified) clang/test/Analysis/Checkers/WebKit/call-args.cpp (+1-1) - (modified) clang/test/Analysis/Checkers/WebKit/mock-types.h (+52-15) ``````````diff diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 9ed8e7cab6abb9..ec1db1cc335807 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -50,6 +50,9 @@ std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class); /// class, false if not, std::nullopt if inconclusive. std::optional<bool> isUncountedPtr(const clang::Type* T); +/// \returns true if Name is a RefPtr, Ref, or its variant, false if not. +bool isRefType(const std::string &Name); + /// \returns true if \p F creates ref-countable object from uncounted parameter, /// false if not. bool isCtorOfRefCounted(const clang::FunctionDecl *F); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp index 8b41a949fd6734..741f336761589f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -53,6 +53,12 @@ class UncountedCallArgsChecker bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return false; } + bool TraverseDecl(Decl *D) { + if (isa<ClassTemplateDecl>(D) && isRefType(safeGetName(D))) + return true; + return RecursiveASTVisitor<LocalVisitor>::TraverseDecl(D); + } + bool VisitCallExpr(const CallExpr *CE) { Checker->visitCallExpr(CE); return true; diff --git a/clang/test/Analysis/Checkers/WebKit/call-args.cpp b/clang/test/Analysis/Checkers/WebKit/call-args.cpp index f2e1f9bc5a2464..2a4b6bb1f1063a 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args.cpp @@ -32,7 +32,7 @@ namespace ref_counted { void consume_ref_counted(Ref<RefCountable>) {} void foo() { - consume_refcntbl(provide_ref_counted().get()); + consume_refcntbl(provide_ref_counted().ptr()); // no warning } } diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index aab99197dfa49e..c27ea9baaf3bf5 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -1,24 +1,61 @@ #ifndef mock_types_1103988513531 #define mock_types_1103988513531 -template <typename T> struct Ref { - T *t; +template<typename T> +struct RawPtrTraits { + using StorageType = T*; - Ref() : t{} {}; - Ref(T &t) - : t(t) { - if (t) - t->ref(); + template<typename U> + static T* exchange(StorageType& ptr, U&& newValue) + { + StorageType oldValue = static_cast<StorageType&&>(ptr); + ptr = static_cast<U&&>(newValue); + return oldValue; } - ~Ref() { - if (t) - t->deref(); + + static void swap(StorageType& a, StorageType& b) + { + StorageType temp = static_cast<StorageType&&>(a); + a = static_cast<StorageType&&>(b); + b = static_cast<StorageType&&>(temp); } - T *get() { return t; } - T *ptr() { return t; } - T *operator->() { return t; } - operator const T &() const { return *t; } - operator T &() { return *t; } + static T* unwrap(const StorageType& ptr) { return ptr; } +}; + +template<typename T> struct DefaultRefDerefTraits { + static T* refIfNotNull(T* ptr) + { + if (ptr) + ptr->ref(); + return ptr; + } + + static T& ref(T& ref) + { + ref.ref(); + return ref; + } + + static void derefIfNotNull(T* ptr) + { + if (ptr) + ptr->deref(); + } +}; + +template <typename T, typename PtrTraits = RawPtrTraits<T>, typename RefDerefTraits = DefaultRefDerefTraits<T>> struct Ref { + typename PtrTraits::StorageType t; + + Ref() : t{} {}; + Ref(T &t) : t(RefDerefTraits::refIfNotNull(t)) { } + Ref(const Ref& o) : t(RefDerefTraits::refIfNotNull(PtrTraits::unwrap(o.t))) { } + ~Ref() { RefDerefTraits::derefIfNotNull(PtrTraits::exchange(t, nullptr)); } + T &get() { return *PtrTraits::unwrap(t); } + T *ptr() { return PtrTraits::unwrap(t); } + T *operator->() { return PtrTraits::unwrap(t); } + operator const T &() const { return *PtrTraits::unwrap(t); } + operator T &() { return *PtrTraits::unwrap(t); } + T* leakRef() { PtrTraits::exchange(t, nullptr); } }; template <typename T> struct RefPtr { `````````` </details> https://github.com/llvm/llvm-project/pull/90153 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits