1 // RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-unused-local-non-trivial-variable %t -- \ 2 // RUN: -config="{CheckOptions: {bugprone-unused-local-non-trivial-variable.IncludeTypes: '::async::Future;::async::Foo.*', bugprone-unused-local-non-trivial-variable.ExcludeTypes: '::async::FooBar'}}" \ 3 // RUN: -- -fexceptions 4 5 namespace async { 6 template <typename T> 7 class Ptr { 8 public: 9 explicit Ptr(T Arg) : Underlying(new T(Arg)) {} 10 T& operator->() { 11 return Underlying; 12 } 13 ~Ptr() { 14 delete Underlying; 15 } 16 private: 17 T* Underlying; 18 }; 19 20 template<typename T> 21 class Future { 22 public: 23 T get() { 24 return Pending; 25 } 26 ~Future(); 27 private: 28 T Pending; 29 }; 30 31 class FooBar { 32 public: 33 ~FooBar(); 34 private: 35 Future<int> Fut; 36 }; 37 38 class FooQux { 39 public: 40 ~FooQux(); 41 private: 42 Future<int> Fut; 43 }; 44 45 class FizzFoo { 46 public: 47 ~FizzFoo(); 48 private: 49 Future<int> Fut; 50 }; 51 52 } // namespace async 53 54 // Warning is still emitted if there are type aliases. 55 namespace a { 56 template<typename T> 57 using Future = async::Future<T>; 58 } // namespace a 59 60 void releaseUnits(); 61 struct Units { 62 ~Units() { 63 releaseUnits(); 64 } 65 }; 66 a::Future<Units> acquireUnits(); 67 68 template<typename T> 69 T qux(T Generic) { 70 async::Future<Units> PendingA = acquireUnits(); 71 auto PendingB = acquireUnits(); 72 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable] 73 async::Future<Units> MustBeUsed; 74 // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: unused local variable 'MustBeUsed' of type 'async::Future<Units>' [bugprone-unused-local-non-trivial-variable] 75 PendingA.get(); 76 async::Future<T> TemplateType; 77 // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable] 78 a::Future<T> AliasTemplateType; 79 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<T>') [bugprone-unused-local-non-trivial-variable] 80 [[maybe_unused]] async::Future<Units> MaybeUnused; 81 return Generic; 82 } 83 84 async::Future<int> Global; 85 86 int bar(int Num) { 87 a::Future<Units> PendingA = acquireUnits(); 88 a::Future<Units> PendingB = acquireUnits(); // not used at all, unused variable not fired because of destructor side effect 89 // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable] 90 auto Num2 = PendingA.get(); 91 auto Num3 = qux(Num); 92 async::Ptr<a::Future<Units>> Shared = async::Ptr<a::Future<Units>>(acquireUnits()); 93 static auto UnusedStatic = async::Future<Units>(); 94 thread_local async::Future<Units> UnusedThreadLocal; 95 auto Captured = acquireUnits(); 96 Num3 += [Captured]() { 97 return 1; 98 }(); 99 a::Future<Units> Referenced = acquireUnits(); 100 a::Future<Units>* Pointer = &Referenced; 101 a::Future<Units>& Reference = Referenced; 102 const a::Future<Units>& ConstReference = Referenced; 103 try { 104 } catch (a::Future<Units> Fut) { 105 } 106 struct Holder { 107 a::Future<Units> Fut; 108 }; 109 Holder H; 110 auto [fut] = H; 111 return Num * Num3; 112 } 113 114 void exclusion() { 115 async::FizzFoo A; 116 async::FooBar B; 117 async::FooQux C; 118 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: unused local variable 'C' of type 'async::FooQux' [bugprone-unused-local-non-trivial-variable] 119 } 120