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