// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-unused-local-non-trivial-variable %t -- \
// RUN: -config="{CheckOptions: {bugprone-unused-local-non-trivial-variable.IncludeTypes: '::async::Future;::async::Foo.*', bugprone-unused-local-non-trivial-variable.ExcludeTypes: '::async::FooBar'}}" \
// RUN: -- -fexceptions
namespace async {
template <typename T>
class Ptr {
public:
explicit Ptr(T Arg) : Underlying(new T(Arg)) {}
T& operator->() {
return Underlying;
}
~Ptr() {
delete Underlying;
}
private:
T* Underlying;
};
template<typename T>
class Future {
public:
T get() {
return Pending;
}
~Future();
private:
T Pending;
};
class FooBar {
public:
~FooBar();
private:
Future<int> Fut;
};
class FooQux {
public:
~FooQux();
private:
Future<int> Fut;
};
class FizzFoo {
public:
~FizzFoo();
private:
Future<int> Fut;
};
} // namespace async
// Warning is still emitted if there are type aliases.
namespace a {
template<typename T>
using Future = async::Future<T>;
} // namespace a
void releaseUnits();
struct Units {
~Units() {
releaseUnits();
}
};
a::Future<Units> acquireUnits();
template<typename T>
T qux(T Generic) {
async::Future<Units> PendingA = acquireUnits();
auto PendingB = acquireUnits();
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
async::Future<Units> MustBeUsed;
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: unused local variable 'MustBeUsed' of type 'async::Future<Units>' [bugprone-unused-local-non-trivial-variable]
PendingA.get();
async::Future<T> TemplateType;
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable]
a::Future<T> AliasTemplateType;
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<T>') [bugprone-unused-local-non-trivial-variable]
[[maybe_unused]] async::Future<Units> MaybeUnused;
return Generic;
}
async::Future<int> Global;
int bar(int Num) {
a::Future<Units> PendingA = acquireUnits();
a::Future<Units> PendingB = acquireUnits(); // not used at all, unused variable not fired because of destructor side effect
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
auto Num2 = PendingA.get();
auto Num3 = qux(Num);
async::Ptr<a::Future<Units>> Shared = async::Ptr<a::Future<Units>>(acquireUnits());
static auto UnusedStatic = async::Future<Units>();
thread_local async::Future<Units> UnusedThreadLocal;
auto Captured = acquireUnits();
Num3 += [Captured]() {
return 1;
}();
a::Future<Units> Referenced = acquireUnits();
a::Future<Units>* Pointer = &Referenced;
a::Future<Units>& Reference = Referenced;
const a::Future<Units>& ConstReference = Referenced;
try {
} catch (a::Future<Units> Fut) {
}
struct Holder {
a::Future<Units> Fut;
};
Holder H;
auto [fut] = H;
return Num * Num3;
}
void exclusion() {
async::FizzFoo A;
async::FooBar B;
async::FooQux C;
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: unused local variable 'C' of type 'async::FooQux' [bugprone-unused-local-non-trivial-variable]
}