1952d344fSTyler Rockwood // RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-unused-local-non-trivial-variable %t -- \
237fc9c6aSPiotr Zegar // RUN:       -config="{CheckOptions: {bugprone-unused-local-non-trivial-variable.IncludeTypes: '::async::Future;::async::Foo.*', bugprone-unused-local-non-trivial-variable.ExcludeTypes: '::async::FooBar'}}" \
3007ed0dcSPiotr Zegar // RUN:       -- -fexceptions
4952d344fSTyler Rockwood 
5952d344fSTyler Rockwood namespace async {
6952d344fSTyler Rockwood template <typename T>
7952d344fSTyler Rockwood class Ptr {
8952d344fSTyler Rockwood   public:
9952d344fSTyler Rockwood   explicit Ptr(T Arg) : Underlying(new T(Arg)) {}
10952d344fSTyler Rockwood   T& operator->() {
11952d344fSTyler Rockwood     return Underlying;
12952d344fSTyler Rockwood   }
13952d344fSTyler Rockwood   ~Ptr() {
14952d344fSTyler Rockwood     delete Underlying;
15952d344fSTyler Rockwood   }
16952d344fSTyler Rockwood   private:
17952d344fSTyler Rockwood     T* Underlying;
18952d344fSTyler Rockwood };
19952d344fSTyler Rockwood 
20952d344fSTyler Rockwood template<typename T>
21952d344fSTyler Rockwood class Future {
22952d344fSTyler Rockwood public:
23952d344fSTyler Rockwood     T get() {
24952d344fSTyler Rockwood         return Pending;
25952d344fSTyler Rockwood     }
26952d344fSTyler Rockwood     ~Future();
27952d344fSTyler Rockwood private:
28952d344fSTyler Rockwood     T Pending;
29952d344fSTyler Rockwood };
30952d344fSTyler Rockwood 
31952d344fSTyler Rockwood class FooBar {
32952d344fSTyler Rockwood   public:
33952d344fSTyler Rockwood     ~FooBar();
34952d344fSTyler Rockwood   private:
35952d344fSTyler Rockwood     Future<int> Fut;
36952d344fSTyler Rockwood };
37952d344fSTyler Rockwood 
38952d344fSTyler Rockwood class FooQux {
39952d344fSTyler Rockwood   public:
40952d344fSTyler Rockwood     ~FooQux();
41952d344fSTyler Rockwood   private:
42952d344fSTyler Rockwood     Future<int> Fut;
43952d344fSTyler Rockwood };
44952d344fSTyler Rockwood 
45952d344fSTyler Rockwood class FizzFoo {
46952d344fSTyler Rockwood   public:
47952d344fSTyler Rockwood     ~FizzFoo();
48952d344fSTyler Rockwood   private:
49952d344fSTyler Rockwood     Future<int> Fut;
50952d344fSTyler Rockwood };
51952d344fSTyler Rockwood 
52952d344fSTyler Rockwood } // namespace async
53952d344fSTyler Rockwood 
54952d344fSTyler Rockwood // Warning is still emitted if there are type aliases.
55952d344fSTyler Rockwood namespace a {
56952d344fSTyler Rockwood template<typename T>
57952d344fSTyler Rockwood using Future = async::Future<T>;
58952d344fSTyler Rockwood } // namespace a
59952d344fSTyler Rockwood 
60952d344fSTyler Rockwood void releaseUnits();
61952d344fSTyler Rockwood struct Units {
62952d344fSTyler Rockwood   ~Units() {
63952d344fSTyler Rockwood     releaseUnits();
64952d344fSTyler Rockwood   }
65952d344fSTyler Rockwood };
66952d344fSTyler Rockwood a::Future<Units> acquireUnits();
67952d344fSTyler Rockwood 
68952d344fSTyler Rockwood template<typename T>
69952d344fSTyler Rockwood T qux(T Generic) {
70952d344fSTyler Rockwood     async::Future<Units> PendingA = acquireUnits();
71952d344fSTyler Rockwood     auto PendingB = acquireUnits();
72952d344fSTyler Rockwood     // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
73952d344fSTyler Rockwood     async::Future<Units> MustBeUsed;
74952d344fSTyler Rockwood     // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: unused local variable 'MustBeUsed' of type 'async::Future<Units>' [bugprone-unused-local-non-trivial-variable]
75952d344fSTyler Rockwood     PendingA.get();
76952d344fSTyler Rockwood     async::Future<T> TemplateType;
77952d344fSTyler Rockwood     // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable]
78952d344fSTyler Rockwood     a::Future<T> AliasTemplateType;
79*7f78f99fSMatheus Izvekov     // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<T>') [bugprone-unused-local-non-trivial-variable]
80ebe77cc3SCongcong Cai     [[maybe_unused]] async::Future<Units> MaybeUnused;
81952d344fSTyler Rockwood     return Generic;
82952d344fSTyler Rockwood }
83952d344fSTyler Rockwood 
84952d344fSTyler Rockwood async::Future<int> Global;
85952d344fSTyler Rockwood 
86952d344fSTyler Rockwood int bar(int Num) {
87952d344fSTyler Rockwood     a::Future<Units> PendingA = acquireUnits();
88952d344fSTyler Rockwood     a::Future<Units> PendingB = acquireUnits(); // not used at all, unused variable not fired because of destructor side effect
89952d344fSTyler Rockwood     // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
90952d344fSTyler Rockwood     auto Num2 = PendingA.get();
91952d344fSTyler Rockwood     auto Num3 = qux(Num);
92952d344fSTyler Rockwood     async::Ptr<a::Future<Units>> Shared = async::Ptr<a::Future<Units>>(acquireUnits());
93952d344fSTyler Rockwood     static auto UnusedStatic = async::Future<Units>();
94952d344fSTyler Rockwood     thread_local async::Future<Units> UnusedThreadLocal;
95952d344fSTyler Rockwood     auto Captured = acquireUnits();
96952d344fSTyler Rockwood     Num3 += [Captured]() {
97952d344fSTyler Rockwood       return 1;
98952d344fSTyler Rockwood     }();
99952d344fSTyler Rockwood     a::Future<Units> Referenced = acquireUnits();
100952d344fSTyler Rockwood     a::Future<Units>* Pointer = &Referenced;
101952d344fSTyler Rockwood     a::Future<Units>& Reference = Referenced;
102952d344fSTyler Rockwood     const a::Future<Units>& ConstReference = Referenced;
103952d344fSTyler Rockwood     try {
104952d344fSTyler Rockwood     } catch (a::Future<Units> Fut) {
105952d344fSTyler Rockwood     }
106952d344fSTyler Rockwood     struct Holder {
107952d344fSTyler Rockwood       a::Future<Units> Fut;
108952d344fSTyler Rockwood     };
109952d344fSTyler Rockwood     Holder H;
110952d344fSTyler Rockwood     auto [fut] = H;
111952d344fSTyler Rockwood     return Num * Num3;
112952d344fSTyler Rockwood }
113952d344fSTyler Rockwood 
114952d344fSTyler Rockwood void exclusion() {
115952d344fSTyler Rockwood   async::FizzFoo A;
116952d344fSTyler Rockwood   async::FooBar B;
117952d344fSTyler Rockwood   async::FooQux C;
118952d344fSTyler Rockwood   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: unused local variable 'C' of type 'async::FooQux' [bugprone-unused-local-non-trivial-variable]
119952d344fSTyler Rockwood }
120