https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/115594
>From 28ee8321eb6e405fd1ebae9043c3ffafe20a4b35 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <rn...@webkit.org> Date: Sat, 9 Nov 2024 00:14:36 -0800 Subject: [PATCH 1/2] [Webkit Checkers] Treat const member variables as a safe origin Treat const Ref, RefPtr, CheckedRef, CheckedPtr member variables as safe pointer origin in WebKit's local variable and call arguments checkers. --- .../Checkers/WebKit/ASTUtils.cpp | 6 +++ .../WebKit/RawPtrRefLocalVarsChecker.cpp | 8 +++ .../WebKit/call-args-checked-const-member.cpp | 43 ++++++++++++++++ .../WebKit/call-args-counted-const-member.cpp | 43 ++++++++++++++++ .../local-vars-checked-const-member.cpp | 50 +++++++++++++++++++ .../local-vars-counted-const-member.cpp | 50 +++++++++++++++++++ .../Analysis/Checkers/WebKit/mock-types.h | 25 ++++------ 7 files changed, 211 insertions(+), 14 deletions(-) create mode 100644 clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp create mode 100644 clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp create mode 100644 clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp create mode 100644 clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index 9d34dfd3cea636..ad2be6f6793cea 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -142,6 +142,12 @@ bool isASafeCallArg(const Expr *E) { return true; } } + if (auto *ME = dyn_cast<MemberExpr>(E)) { + if (auto *D = ME->getMemberDecl()) { + auto T = D->getType(); + return isSafePtrType(T) && T.isConstQualified(); + } + } // TODO: checker for method calls on non-refcounted objects return isa<CXXThisExpr>(E); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp index 06f8f43cee8151..be954ad3026c22 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp @@ -281,6 +281,14 @@ class RawPtrRefLocalVarsChecker if (isa<IntegerLiteral>(InitArgOrigin)) return true; + if (auto *ME = dyn_cast<MemberExpr>(InitArgOrigin)) { + if (auto *D = ME->getMemberDecl()) { + auto T = D->getType(); + if (isSafePtrType(T) && T.isConstQualified()) + return true; + } + } + if (auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) { if (auto *MaybeGuardian = dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) { diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp new file mode 100644 index 00000000000000..6a54ac7b2ca791 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s + +#include "mock-types.h" + +namespace call_args_const_checkedptr_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const CheckedPtr<CheckedObj> m_obj1; + CheckedPtr<CheckedObj> m_obj2; +}; + +void Foo::bar() { + m_obj1->method(); + m_obj2->method(); + // expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}} +} + +} // namespace call_args_const_checkedptr_member + +namespace call_args_const_checkedref_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const CheckedRef<CheckedObj> m_obj1; + CheckedRef<CheckedObj> m_obj2; +}; + +void Foo::bar() { + m_obj1->method(); + m_obj2->method(); + // expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}} +} + +} // namespace call_args_const_checkedref_member diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp new file mode 100644 index 00000000000000..33af5ad9014de4 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s + +#include "mock-types.h" + +namespace call_args_const_refptr_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const RefPtr<RefCountable> m_obj1; + RefPtr<RefCountable> m_obj2; +}; + +void Foo::bar() { + m_obj1->method(); + m_obj2->method(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} +} + +} // namespace call_args_const_refptr_member + +namespace call_args_const_ref_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const Ref<RefCountable> m_obj1; + Ref<RefCountable> m_obj2; +}; + +void Foo::bar() { + m_obj1->method(); + m_obj2->method(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} +} + +} // namespace call_args_const_ref_member diff --git a/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp new file mode 100644 index 00000000000000..3deef66c271096 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedLocalVarsChecker -verify %s + +#include "mock-types.h" +#include "mock-system-header.h" + +void someFunction(); + +namespace local_vars_const_checkedptr_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const CheckedPtr<CheckedObj> m_obj1; + CheckedPtr<CheckedObj> m_obj2; +}; + +void Foo::bar() { + auto* obj1 = m_obj1.get(); + obj1->method(); + auto* obj2 = m_obj2.get(); + // expected-warning@-1{{Local variable 'obj2' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} + obj2->method(); +} + +} // namespace local_vars_const_checkedptr_member + +namespace local_vars_const_checkedref_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const CheckedRef<CheckedObj> m_obj1; + CheckedRef<CheckedObj> m_obj2; +}; + +void Foo::bar() { + auto& obj1 = m_obj1.get(); + obj1.method(); + auto& obj2 = m_obj2.get(); + // expected-warning@-1{{Local variable 'obj2' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} + obj2.method(); +} + +} // namespace local_vars_const_ref_member diff --git a/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp new file mode 100644 index 00000000000000..6d6a7718244002 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedLocalVarsChecker -verify %s + +#include "mock-types.h" +#include "mock-system-header.h" + +void someFunction(); + +namespace local_vars_const_refptr_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const RefPtr<RefCountable> m_obj1; + RefPtr<RefCountable> m_obj2; +}; + +void Foo::bar() { + auto* obj1 = m_obj1.get(); + obj1->method(); + auto* obj2 = m_obj2.get(); + // expected-warning@-1{{Local variable 'obj2' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + obj2->method(); +} + +} // namespace local_vars_const_refptr_member + +namespace local_vars_const_ref_member { + +class Foo { +public: + Foo(); + void bar(); + +private: + const Ref<RefCountable> m_obj1; + Ref<RefCountable> m_obj2; +}; + +void Foo::bar() { + auto& obj1 = m_obj1.get(); + obj1.method(); + auto& obj2 = m_obj2.get(); + // expected-warning@-1{{Local variable 'obj2' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + obj2.method(); +} + +} // namespace local_vars_const_ref_member diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index 9c9326f0f11cfb..8f84589477bff1 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -66,11 +66,10 @@ template <typename T, typename PtrTraits = RawPtrTraits<T>, typename RefDerefTra t = o.t; o.t = tmp; } - 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 &get() const { return *PtrTraits::unwrap(t); } + T *ptr() const { return PtrTraits::unwrap(t); } + T *operator->() const { return PtrTraits::unwrap(t); } + operator T &() const { return *PtrTraits::unwrap(t); } T* leakRef() { return PtrTraits::exchange(t, nullptr); } }; @@ -102,9 +101,8 @@ template <typename T> struct RefPtr { t = o.t; o.t = tmp; } - T *get() { return t; } - T *operator->() { return t; } - const T *operator->() const { return t; } + T *get() const { return t; } + T *operator->() const { return t; } T &operator*() { return *t; } RefPtr &operator=(T *t) { RefPtr o(t); @@ -149,9 +147,9 @@ template <typename T> struct CheckedRef { CheckedRef(T &t) : t(&t) { t.incrementCheckedPtrCount(); } CheckedRef(const CheckedRef &o) : t(o.t) { if (t) t->incrementCheckedPtrCount(); } ~CheckedRef() { if (t) t->decrementCheckedPtrCount(); } - T &get() { return *t; } - T *ptr() { return t; } - T *operator->() { return t; } + T &get() const { return *t; } + T *ptr() const { return t; } + T *operator->() const { return t; } operator const T &() const { return *t; } operator T &() { return *t; } }; @@ -174,9 +172,8 @@ template <typename T> struct CheckedPtr { if (t) t->decrementCheckedPtrCount(); } - T *get() { return t; } - T *operator->() { return t; } - const T *operator->() const { return t; } + T *get() const { return t; } + T *operator->() const { return t; } T &operator*() { return *t; } CheckedPtr &operator=(T *) { return *this; } operator bool() const { return t; } >From 8bda96559ff4fc50a76b25a1879cc7fc2c828616 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <rn...@webkit.org> Date: Tue, 12 Nov 2024 23:14:57 -0800 Subject: [PATCH 2/2] Add the support for treating const unique_ptr as a safe pointer origin. Also allow .get() and .ptr() on const member variable. --- .../Checkers/WebKit/ASTUtils.cpp | 28 +++++++++++++++---- .../StaticAnalyzer/Checkers/WebKit/ASTUtils.h | 3 ++ .../Checkers/WebKit/PtrTypesSemantics.cpp | 22 +++++++++++---- .../Checkers/WebKit/PtrTypesSemantics.h | 4 +++ .../WebKit/RawPtrRefLocalVarsChecker.cpp | 9 ++---- .../WebKit/call-args-checked-const-member.cpp | 20 +++++++++++++ .../WebKit/call-args-counted-const-member.cpp | 23 +++++++++++++++ .../local-vars-checked-const-member.cpp | 22 +++++++++++++++ .../local-vars-counted-const-member.cpp | 22 +++++++++++++++ .../Analysis/Checkers/WebKit/mock-types.h | 27 ++++++++++++++++++ 10 files changed, 162 insertions(+), 18 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index ad2be6f6793cea..b3cd594a0f3529 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -142,15 +142,31 @@ bool isASafeCallArg(const Expr *E) { return true; } } - if (auto *ME = dyn_cast<MemberExpr>(E)) { - if (auto *D = ME->getMemberDecl()) { - auto T = D->getType(); - return isSafePtrType(T) && T.isConstQualified(); - } - } + if (isConstOwnerPtrMemberExpr(E)) + return true; // TODO: checker for method calls on non-refcounted objects return isa<CXXThisExpr>(E); } +bool isConstOwnerPtrMemberExpr(const clang::Expr *E) { + if (auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) { + if (auto *Callee = MCE->getDirectCallee()) { + auto Name = safeGetName(Callee); + if (Name == "get" || Name == "ptr") { + auto *ThisArg = MCE->getImplicitObjectArgument(); + E = ThisArg; + } + } + } + auto *ME = dyn_cast<MemberExpr>(E); + if (!ME) + return false; + auto *D = ME->getMemberDecl(); + if (!D) + return false; + auto T = D->getType(); + return isOwnerPtrType(T) && T.isConstQualified(); +} + } // namespace clang diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h index e972924e0c523d..ddbef0fba04489 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -64,6 +64,9 @@ bool tryToFindPtrOrigin( /// \returns Whether \p E is a safe call arugment. bool isASafeCallArg(const clang::Expr *E); +/// \returns true if E is a MemberExpr accessing a const smart pointer type. +bool isConstOwnerPtrMemberExpr(const clang::Expr *E); + /// \returns name of AST node or empty string. template <typename T> std::string safeGetName(const T *ASTNode) { const auto *const ND = llvm::dyn_cast_or_null<clang::NamedDecl>(ASTNode); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 31bebdb07dbdc2..b168fc4dc75e7f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -145,7 +145,8 @@ bool isCtorOfSafePtr(const clang::FunctionDecl *F) { return isCtorOfRefCounted(F) || isCtorOfCheckedPtr(F); } -bool isSafePtrType(const clang::QualType T) { +template <typename Predicate> +static bool isPtrOfType(const clang::QualType T, Predicate Pred) { QualType type = T; while (!type.isNull()) { if (auto *elaboratedT = type->getAs<ElaboratedType>()) { @@ -153,10 +154,8 @@ bool isSafePtrType(const clang::QualType T) { continue; } if (auto *specialT = type->getAs<TemplateSpecializationType>()) { - if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) { - auto name = decl->getNameAsString(); - return isRefType(name) || isCheckedPtr(name); - } + if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) + return Pred(decl->getNameAsString()); return false; } return false; @@ -164,6 +163,19 @@ bool isSafePtrType(const clang::QualType T) { return false; } +bool isSafePtrType(const clang::QualType T) { + return isPtrOfType(T, [](auto Name) { + return isRefType(Name) || isCheckedPtr(Name); + }); +} + +bool isOwnerPtrType(const clang::QualType T) { + return isPtrOfType(T, [](auto Name) { + return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" || + Name == "UniqueRef" || Name == "LazyUniqueRef"; + }); +} + std::optional<bool> isUncounted(const QualType T) { if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) { if (auto *Decl = Subst->getAssociatedDecl()) { diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 7c6c0a63f22aba..e9af4d8a0878e3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -79,6 +79,10 @@ std::optional<bool> isUncheckedPtr(const clang::QualType T); /// variant, false if not. bool isSafePtrType(const clang::QualType T); +/// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or +/// unique_ptr, false if not. +bool isOwnerPtrType(const clang::QualType T); + /// \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/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp index be954ad3026c22..48c3dc4c94477a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp @@ -281,13 +281,8 @@ class RawPtrRefLocalVarsChecker if (isa<IntegerLiteral>(InitArgOrigin)) return true; - if (auto *ME = dyn_cast<MemberExpr>(InitArgOrigin)) { - if (auto *D = ME->getMemberDecl()) { - auto T = D->getType(); - if (isSafePtrType(T) && T.isConstQualified()) - return true; - } - } + if (isConstOwnerPtrMemberExpr(InitArgOrigin)) + return true; if (auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) { if (auto *MaybeGuardian = diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp index 6a54ac7b2ca791..76f80a12c1703c 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp @@ -41,3 +41,23 @@ void Foo::bar() { } } // namespace call_args_const_checkedref_member + +namespace call_args_const_unique_ptr { + +class Foo { +public: + Foo(); + void bar(); + +private: + const std::unique_ptr<CheckedObj> m_obj1; + std::unique_ptr<CheckedObj> m_obj2; +}; + +void Foo::bar() { + m_obj1->method(); + m_obj2->method(); + // expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}} +} + +} // namespace call_args_const_unique_ptr diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp index 33af5ad9014de4..cf47f744a44617 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp @@ -2,6 +2,9 @@ #include "mock-types.h" +namespace std { +} + namespace call_args_const_refptr_member { class Foo { @@ -41,3 +44,23 @@ void Foo::bar() { } } // namespace call_args_const_ref_member + +namespace call_args_const_unique_ptr { + +class Foo { +public: + Foo(); + void bar(); + +private: + const std::unique_ptr<RefCountable> m_obj1; + std::unique_ptr<RefCountable> m_obj2; +}; + +void Foo::bar() { + m_obj1->method(); + m_obj2->method(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} +} + +} // namespace call_args_const_unique_ptr diff --git a/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp index 3deef66c271096..e52d1e735f6379 100644 --- a/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp @@ -48,3 +48,25 @@ void Foo::bar() { } } // namespace local_vars_const_ref_member + +namespace call_args_const_unique_ptr { + +class Foo { +public: + Foo(); + void bar(); + +private: + const std::unique_ptr<CheckedObj> m_obj1; + std::unique_ptr<CheckedObj> m_obj2; +}; + +void Foo::bar() { + auto* obj1 = m_obj1.get(); + obj1->method(); + auto* obj2 = m_obj2.get(); + // expected-warning@-1{{Local variable 'obj2' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} + obj2->method(); +} + +} // namespace call_args_const_unique_ptr diff --git a/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp index 6d6a7718244002..03d16285f88b53 100644 --- a/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp @@ -48,3 +48,25 @@ void Foo::bar() { } } // namespace local_vars_const_ref_member + +namespace call_args_const_unique_ptr { + +class Foo { +public: + Foo(); + void bar(); + +private: + const std::unique_ptr<RefCountable> m_obj1; + std::unique_ptr<RefCountable> m_obj2; +}; + +void Foo::bar() { + auto* obj1 = m_obj1.get(); + obj1->method(); + auto* obj2 = m_obj2.get(); + // expected-warning@-1{{Local variable 'obj2' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + obj2->method(); +} + +} // namespace call_args_const_unique_ptr diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index 8f84589477bff1..5dcf23a388c492 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -197,4 +197,31 @@ class RefCountableAndCheckable { int trivial() { return 0; } }; +namespace std { + +template <typename T> +class unique_ptr { +private: + T *t; + +public: + unique_ptr() : t(nullptr) { } + unique_ptr(T *t) : t(t) { } + ~unique_ptr() { + if (t) + delete t; + } + template <typename U> unique_ptr(unique_ptr<U>&& u) + : t(u.t) + { + u.t = nullptr; + } + T *get() const { return t; } + T *operator->() const { return t; } + T &operator*() { return *t; } + unique_ptr &operator=(T *) { return *this; } +}; + +}; + #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits