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
5namespace async {
6template <typename T>
7class 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
20template<typename T>
21class Future {
22public:
23 T get() {
24 return Pending;
25 }
26 ~Future();
27private:
28 T Pending;
29};
30
31class FooBar {
32 public:
33 ~FooBar();
34 private:
35 Future<int> Fut;
36};
37
38class FooQux {
39 public:
40 ~FooQux();
41 private:
42 Future<int> Fut;
43};
44
45class 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.
55namespace a {
56template<typename T>
57using Future = async::Future<T>;
58} // namespace a
59
60void releaseUnits();
61struct Units {
62 ~Units() {
63 releaseUnits();
64 }
65};
66a::Future<Units> acquireUnits();
67
68template<typename T>
69T 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<type-parameter-0-0>') [bugprone-unused-local-non-trivial-variable]
80 [[maybe_unused]] async::Future<Units> MaybeUnused;
81 return Generic;
82}
83
84async::Future<int> Global;
85
86int 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(Generic: 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
114void 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

source code of clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp