[clang-tools-extra] r374540 - [ClangTidy] Separate tests for infrastructure and checkers
Dmitri Gribenko via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 11 05:05:46 PDT 2019
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-parent-virtual-call.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-parent-virtual-call.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-parent-virtual-call.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-parent-virtual-call.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,179 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+ A() = default;
+ virtual ~A() = default;
+
+ virtual int virt_1() { return foo() + 1; }
+ virtual int virt_2() { return foo() + 2; }
+
+ int non_virt() { return foo() + 3; }
+ static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+ B() = default;
+
+ // Nothing to fix: calls to direct parent.
+ int virt_1() override { return A::virt_1() + 3; }
+ int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+ int virt_1() override { return A::virt_1() + B::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' refers to a member overridden in subclass; did you mean 'B'? [bugprone-parent-virtual-call]
+ // CHECK-FIXES: int virt_1() override { return B::virt_1() + B::virt_1(); }
+ int virt_2() override { return A::virt_1() + B::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+ // Test that non-virtual and static methods are not affected by this cherker.
+ int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Check aliased type names
+using A1 = A;
+typedef A A2;
+#define A3 A
+
+class C2 : public B {
+public:
+ int virt_1() override { return A1::virt_1() + A2::virt_1() + A3::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A1::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-2]]:49: warning: qualified name 'A2::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-3]]:64: warning: qualified name 'A3::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return B::virt_1() + B::virt_1() + B::virt_1(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+ int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name 'B::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+ int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name 'B::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in namespaces.
+namespace {
+class BN : public A {
+public:
+ int virt_1() override { return A::virt_1() + 3; }
+ int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace
+
+namespace N1 {
+class A {
+public:
+ A() = default;
+ virtual int virt_1() { return foo() + 1; }
+ virtual int virt_2() { return foo() + 2; }
+};
+} // namespace N1
+
+namespace N2 {
+class BN : public N1::A {
+public:
+ int virt_1() override { return A::virt_1() + 3; }
+ int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N2
+
+class CN : public BN {
+public:
+ int virt_1() override { return A::virt_1() + BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BN'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+ int virt_2() override { return A::virt_1() + BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BN'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+class CNN : public N2::BN {
+public:
+ int virt_1() override { return N1::A::virt_1() + N2::BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'N1::A::virt_1' {{.*}}; did you mean 'N2::BN'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return N2::BN::virt_1() + N2::BN::virt_1(); }
+ int virt_2() override { return N1::A::virt_1() + N2::BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'N1::A::virt_1' {{.*}}; did you mean 'N2::BN'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return N2::BN::virt_1() + N2::BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+ AA() = default;
+ virtual ~AA() = default;
+
+ virtual int virt_1() { return foo() + 1; }
+ virtual int virt_2() { return foo() + 2; }
+
+ int non_virt() { return foo() + 3; }
+ static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+ BB_1() = default;
+
+ // Nothing to fix: calls to parent.
+ int virt_1() override { return AA::virt_1() + 3; }
+ int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+ BB_2() = default;
+ int virt_1() override { return AA::virt_1() + 3; }
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+ int virt_1() override { return AA::virt_1() + 3; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'AA::virt_1' refers to a member overridden in subclasses; did you mean 'BB_1' or 'BB_2'? {{.*}}
+ // No fix available due to multiple choice of parent class.
+};
+
+// Test that virtual method is not diagnosed as not overridden in parent.
+class BI : public A {
+public:
+ BI() = default;
+};
+
+class CI : BI {
+ int virt_1() override { return A::virt_1(); }
+};
+
+// Test templated classes.
+template <class F> class BF : public A {
+public:
+ int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF<int> {
+public:
+ int virt_1() override { return A::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BF'? {{.*}}
+};
+
+// Test both templated class and its parent class.
+template <class F> class DF : public BF<F> {
+public:
+ DF() = default;
+ int virt_1() override { return A::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BF'? {{.*}}
+};
+
+// Just to instantiate DF<F>.
+int bar() { return (new DF<int>())->virt_1(); }
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-posix-return.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-posix-return.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-posix-return.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-posix-return.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,207 @@
+// RUN: %check_clang_tidy %s bugprone-posix-return %t
+
+#define NULL nullptr
+#define ZERO 0
+#define NEGATIVE_ONE -1
+
+typedef int pid_t;
+typedef long off_t;
+typedef decltype(sizeof(int)) size_t;
+typedef struct __posix_spawn_file_actions* posix_spawn_file_actions_t;
+typedef struct __posix_spawnattr* posix_spawnattr_t;
+# define __CPU_SETSIZE 1024
+# define __NCPUBITS (8 * sizeof (__cpu_mask))
+typedef unsigned long int __cpu_mask;
+typedef struct
+{
+ __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
+} cpu_set_t;
+typedef struct _opaque_pthread_t *__darwin_pthread_t;
+typedef __darwin_pthread_t pthread_t;
+typedef struct pthread_attr_t_ *pthread_attr_t;
+
+extern "C" int posix_fadvise(int fd, off_t offset, off_t len, int advice);
+extern "C" int posix_fallocate(int fd, off_t offset, off_t len);
+extern "C" int posix_madvise(void *addr, size_t len, int advice);
+extern "C" int posix_memalign(void **memptr, size_t alignment, size_t size);
+extern "C" int posix_openpt(int flags);
+extern "C" int posix_spawn(pid_t *pid, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[]);
+extern "C" int posix_spawnp(pid_t *pid, const char *file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[]);
+extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
+extern "C" int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);
+extern "C" int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
+extern "C" int pthread_attr_init(pthread_attr_t *attr);
+extern "C" int pthread_yield(void);
+
+
+void warningLessThanZero() {
+ if (posix_fadvise(0, 0, 0, 0) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: the comparison always evaluates to false because posix_fadvise always returns non-negative values
+ // CHECK-FIXES: posix_fadvise(0, 0, 0, 0) > 0
+ if (posix_fallocate(0, 0, 0) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning:
+ // CHECK-FIXES: posix_fallocate(0, 0, 0) > 0
+ if (posix_madvise(NULL, 0, 0) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ // CHECK-FIXES: posix_madvise(NULL, 0, 0) > 0
+ if (posix_memalign(NULL, 0, 0) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning:
+ // CHECK-FIXES: posix_memalign(NULL, 0, 0) > 0
+ if (posix_spawn(NULL, NULL, NULL, NULL, {NULL}, {NULL}) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:59: warning:
+ // CHECK-FIXES: posix_spawn(NULL, NULL, NULL, NULL, {NULL}, {NULL}) > 0
+ if (posix_spawnp(NULL, NULL, NULL, NULL, {NULL}, {NULL}) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:60: warning:
+ // CHECK-FIXES: posix_spawnp(NULL, NULL, NULL, NULL, {NULL}, {NULL}) > 0
+ if (pthread_create(NULL, NULL, NULL, NULL) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: the comparison always evaluates to false because pthread_create always returns non-negative values
+ // CHECK-FIXES: pthread_create(NULL, NULL, NULL, NULL) > 0
+ if (pthread_attr_setaffinity_np(NULL, 0, NULL) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:50: warning:
+ // CHECK-FIXES: pthread_attr_setaffinity_np(NULL, 0, NULL) > 0
+ if (pthread_attr_setschedpolicy(NULL, 0) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning:
+ // CHECK-FIXES: pthread_attr_setschedpolicy(NULL, 0) > 0)
+ if (pthread_attr_init(NULL) < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning:
+ // CHECK-FIXES: pthread_attr_init(NULL) > 0
+ if (pthread_yield() < 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning:
+ // CHECK-FIXES: pthread_yield() > 0
+
+}
+
+void warningAlwaysTrue() {
+ if (posix_fadvise(0, 0, 0, 0) >= 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: the comparison always evaluates to true because posix_fadvise always returns non-negative values
+ if (pthread_create(NULL, NULL, NULL, NULL) >= 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: the comparison always evaluates to true because pthread_create always returns non-negative values
+ if (pthread_attr_setaffinity_np(NULL, 0, NULL) >= 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:50: warning:
+ if (pthread_attr_setschedpolicy(NULL, 0) >= 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning:
+ if (pthread_attr_init(NULL) >= 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning:
+ if (pthread_yield() >= 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning:
+
+}
+
+void warningEqualsNegative() {
+ if (posix_fadvise(0, 0, 0, 0) == -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: posix_fadvise
+ if (posix_fadvise(0, 0, 0, 0) != -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_fadvise(0, 0, 0, 0) <= -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_fadvise(0, 0, 0, 0) < -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_fallocate(0, 0, 0) == -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning:
+ if (posix_madvise(NULL, 0, 0) == -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_memalign(NULL, 0, 0) == -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning:
+ if (posix_spawn(NULL, NULL, NULL, NULL, {NULL}, {NULL}) == -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:59: warning:
+ if (posix_spawnp(NULL, NULL, NULL, NULL, {NULL}, {NULL}) == -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:60: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) == -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: pthread_create
+ if (pthread_create(NULL, NULL, NULL, NULL) != -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) <= -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) < -1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+
+}
+
+void WarningWithMacro() {
+ if (posix_fadvise(0, 0, 0, 0) < ZERO) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ // CHECK-FIXES: posix_fadvise(0, 0, 0, 0) > ZERO
+ if (posix_fadvise(0, 0, 0, 0) >= ZERO) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_fadvise(0, 0, 0, 0) == NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_fadvise(0, 0, 0, 0) != NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_fadvise(0, 0, 0, 0) <= NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (posix_fadvise(0, 0, 0, 0) < NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) < ZERO) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+ // CHECK-FIXES: pthread_create(NULL, NULL, NULL, NULL) > ZERO
+ if (pthread_create(NULL, NULL, NULL, NULL) >= ZERO) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) == NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) != NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) <= NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+ if (pthread_create(NULL, NULL, NULL, NULL) < NEGATIVE_ONE) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning:
+
+}
+
+void noWarning() {
+ if (posix_openpt(0) < 0) {}
+ if (posix_openpt(0) <= 0) {}
+ if (posix_openpt(0) == -1) {}
+ if (posix_openpt(0) != -1) {}
+ if (posix_openpt(0) <= -1) {}
+ if (posix_openpt(0) < -1) {}
+ if (posix_fadvise(0, 0, 0, 0) <= 0) {}
+ if (posix_fadvise(0, 0, 0, 0) == 1) {}
+}
+
+namespace i {
+int posix_fadvise(int fd, off_t offset, off_t len, int advice);
+int pthread_yield(void);
+
+void noWarning() {
+ if (posix_fadvise(0, 0, 0, 0) < 0) {}
+ if (posix_fadvise(0, 0, 0, 0) >= 0) {}
+ if (posix_fadvise(0, 0, 0, 0) == -1) {}
+ if (posix_fadvise(0, 0, 0, 0) != -1) {}
+ if (posix_fadvise(0, 0, 0, 0) <= -1) {}
+ if (posix_fadvise(0, 0, 0, 0) < -1) {}
+ if (pthread_yield() < 0) {}
+ if (pthread_yield() >= 0) {}
+ if (pthread_yield() == -1) {}
+ if (pthread_yield() != -1) {}
+ if (pthread_yield() <= -1) {}
+ if (pthread_yield() < -1) {}
+}
+
+} // namespace i
+
+class G {
+ public:
+ int posix_fadvise(int fd, off_t offset, off_t len, int advice);
+ int pthread_yield(void);
+
+ void noWarning() {
+ if (posix_fadvise(0, 0, 0, 0) < 0) {}
+ if (posix_fadvise(0, 0, 0, 0) >= 0) {}
+ if (posix_fadvise(0, 0, 0, 0) == -1) {}
+ if (posix_fadvise(0, 0, 0, 0) != -1) {}
+ if (posix_fadvise(0, 0, 0, 0) <= -1) {}
+ if (posix_fadvise(0, 0, 0, 0) < -1) {}
+ if (pthread_yield() < 0) {}
+ if (pthread_yield() >= 0) {}
+ if (pthread_yield() == -1) {}
+ if (pthread_yield() != -1) {}
+ if (pthread_yield() <= -1) {}
+ if (pthread_yield() < -1) {}
+ }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-container.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-container.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-container.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-container.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s bugprone-sizeof-container %t -- -- -target x86_64-unknown-unknown
+
+namespace std {
+
+typedef unsigned int size_t;
+
+template <typename T>
+struct basic_string {
+ size_t size() const;
+};
+
+template <typename T>
+basic_string<T> operator+(const basic_string<T> &, const T *);
+
+typedef basic_string<char> string;
+
+template <typename T>
+struct vector {
+ size_t size() const;
+};
+
+// std::bitset<> is not a container. sizeof() is reasonable for it.
+template <size_t N>
+struct bitset {
+ size_t size() const;
+};
+
+// std::array<> is, well, an array. sizeof() is reasonable for it.
+template <typename T, size_t N>
+struct array {
+ size_t size() const;
+};
+
+class fake_container1 {
+ size_t size() const; // non-public
+};
+
+struct fake_container2 {
+ size_t size(); // non-const
+};
+
+}
+
+using std::size_t;
+
+#define ARRAYSIZE(a) \
+ ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+#define ARRAYSIZE2(a) \
+ (((sizeof(a)) / (sizeof(*(a)))) / static_cast<size_t>(!((sizeof(a)) % (sizeof(*(a))))))
+
+struct string {
+ std::size_t size() const;
+};
+
+template<typename T>
+void g(T t) {
+ (void)sizeof(t);
+}
+
+void f() {
+ string s1;
+ std::string s2;
+ std::vector<int> v;
+
+ int a = 42 + sizeof(s1);
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: sizeof() doesn't return the size of the container; did you mean .size()? [bugprone-sizeof-container]
+ a = 123 * sizeof(s2);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: sizeof() doesn't return the size
+ a = 45 + sizeof(s2 + "asdf");
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: sizeof() doesn't return the size
+ a = sizeof(v);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
+ a = sizeof(std::vector<int>{});
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
+
+ a = sizeof(a);
+ a = sizeof(int);
+ a = sizeof(std::string);
+ a = sizeof(std::vector<int>);
+
+ g(s1);
+ g(s2);
+ g(v);
+
+ std::fake_container1 fake1;
+ std::fake_container2 fake2;
+ std::bitset<7> std_bitset;
+ std::array<int, 3> std_array;
+
+ a = sizeof(fake1);
+ a = sizeof(fake2);
+ a = sizeof(std_bitset);
+ a = sizeof(std_array);
+
+
+ std::string arr[3];
+ a = ARRAYSIZE(arr);
+ a = ARRAYSIZE2(arr);
+ a = sizeof(arr) / sizeof(arr[0]);
+
+ (void)a;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-expression.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-expression.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-expression.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-sizeof-expression.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,297 @@
+// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- -config="{CheckOptions: [{key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression, value: 1}]}" --
+
+class C {
+ int size() { return sizeof(this); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(this)'
+};
+
+#define LEN 8
+
+int X;
+extern int A[10];
+extern short B[10];
+
+#pragma pack(1)
+struct S { char a, b, c; };
+
+enum E { E_VALUE = 0 };
+enum class EC { VALUE = 0 };
+
+bool AsBool() { return false; }
+int AsInt() { return 0; }
+E AsEnum() { return E_VALUE; }
+EC AsEnumClass() { return EC::VALUE; }
+S AsStruct() { return {}; }
+
+struct M {
+ int AsInt() { return 0; }
+ E AsEnum() { return E_VALUE; }
+ S AsStruct() { return {}; }
+};
+
+int ReturnOverload(int) { return {}; }
+S ReturnOverload(S) { return {}; }
+
+template <class T>
+T ReturnTemplate(T) { return {}; }
+
+template <class T>
+bool TestTrait1() {
+ return sizeof(ReturnOverload(T{})) == sizeof(A);
+}
+
+template <class T>
+bool TestTrait2() {
+ return sizeof(ReturnTemplate(T{})) == sizeof(A);
+}
+
+template <class T>
+bool TestTrait3() {
+ return sizeof(ReturnOverload(0)) == sizeof(T{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+}
+
+template <class T>
+bool TestTrait4() {
+ return sizeof(ReturnTemplate(0)) == sizeof(T{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+}
+
+bool TestTemplates() {
+ bool b = true;
+ b &= TestTrait1<int>();
+ b &= TestTrait1<S>();
+ b &= TestTrait2<int>();
+ b &= TestTrait2<S>();
+ b &= TestTrait3<int>();
+ b &= TestTrait3<S>();
+ b &= TestTrait4<int>();
+ b &= TestTrait4<S>();
+ return b;
+}
+
+int Test1(const char* ptr) {
+ int sum = 0;
+ sum += sizeof(LEN);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
+ sum += sizeof(LEN + 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
+ sum += sizeof(sum, LEN);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(..., ...)'
+ sum += sizeof(AsBool());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(AsInt());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(AsEnum());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(AsEnumClass());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(M{}.AsInt());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(M{}.AsEnum());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + LEN + sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + (LEN + sizeof(X)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + -sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + - + -sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(char) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ sum += sizeof(A) / sizeof(S);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(char) / sizeof(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(char) / sizeof(A);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(B[0]) / sizeof(A);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(ptr) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(ptr) / sizeof(ptr[0]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(ptr) / sizeof(char*);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'
+ sum += sizeof(ptr) / sizeof(void*);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'
+ sum += sizeof(ptr) / sizeof(const void volatile*);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'
+ sum += sizeof(ptr) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(ptr) / sizeof(ptr[0]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(int) * sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ sum += sizeof(ptr) * sizeof(ptr[0]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ sum += sizeof(int) * (2 * sizeof(char));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ sum += (2 * sizeof(char)) * sizeof(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ if (sizeof(A) < 0x100000) sum += 42;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: suspicious comparison of 'sizeof(expr)' to a constant
+ if (sizeof(A) <= 0xFFFFFFFEU) sum += 42;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: suspicious comparison of 'sizeof(expr)' to a constant
+ return sum;
+}
+
+typedef char MyChar;
+typedef const MyChar MyConstChar;
+
+int CE0 = sizeof sizeof(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE1 = sizeof +sizeof(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE2 = sizeof sizeof(const char*);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE3 = sizeof sizeof(const volatile char* const*);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE4 = sizeof sizeof(MyConstChar);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+
+int Test2(MyConstChar* A) {
+ int sum = 0;
+ sum += sizeof(MyConstChar) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ sum += sizeof(MyConstChar) / sizeof(MyChar);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ sum += sizeof(A[0]) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ return sum;
+}
+
+template <int T>
+int Foo() { int A[T]; return sizeof(T); }
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: suspicious usage of 'sizeof(K)'
+template <typename T>
+int Bar() { T A[5]; return sizeof(A[0]) / sizeof(T); }
+// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+int Test3() { return Foo<42>() + Bar<char>(); }
+
+static const char* kABC = "abc";
+static const wchar_t* kDEF = L"def";
+int Test4(const char A[10]) {
+ int sum = 0;
+ sum += sizeof(kABC);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(char*)'
+ sum += sizeof(kDEF);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(char*)'
+ return sum;
+}
+
+int Test5() {
+ typedef int Array10[10];
+
+ struct MyStruct {
+ Array10 arr;
+ Array10* ptr;
+ };
+ typedef const MyStruct TMyStruct;
+ typedef const MyStruct *PMyStruct;
+ typedef TMyStruct *PMyStruct2;
+
+ static TMyStruct kGlocalMyStruct = {};
+ static TMyStruct volatile * kGlocalMyStructPtr = &kGlocalMyStruct;
+
+ MyStruct S;
+ PMyStruct PS;
+ PMyStruct2 PS2;
+ Array10 A10;
+
+ int sum = 0;
+ sum += sizeof(&S.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&kGlocalMyStruct.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&kGlocalMyStructPtr->arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(S.arr + 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(+ S.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof((int*)S.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+
+ sum += sizeof(S.ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(kGlocalMyStruct.ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(kGlocalMyStructPtr->ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+
+ sum += sizeof(&kGlocalMyStruct);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&S);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(MyStruct*);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(PMyStruct);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(PS);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(PS2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&A10);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+
+ return sum;
+}
+
+int Test6() {
+ int sum = 0;
+
+ struct S A = AsStruct(), B = AsStruct();
+ struct S *P = &A, *Q = &B;
+ sum += sizeof(struct S) == P - Q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += 5 * sizeof(S) != P - Q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += sizeof(S) < P - Q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += 5 * sizeof(S) <= P - Q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += 5 * sizeof(*P) >= P - Q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += Q - P > 3 * sizeof(*P);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += sizeof(S) + (P - Q);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += 5 * sizeof(S) - (P - Q);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += (P - Q) / sizeof(S);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+ sum += (P - Q) / sizeof(*Q);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic
+
+ return sum;
+}
+
+int ValidExpressions() {
+ int A[] = {1, 2, 3, 4};
+ static const char str[] = "hello";
+ static const char* ptr[] { "aaa", "bbb", "ccc" };
+ int sum = 0;
+ if (sizeof(A) < 10)
+ sum += sizeof(A);
+ sum += sizeof(int);
+ sum += sizeof(AsStruct());
+ sum += sizeof(M{}.AsStruct());
+ sum += sizeof(A[sizeof(A) / sizeof(int)]);
+ sum += sizeof(&A[sizeof(A) / sizeof(int)]);
+ sum += sizeof(sizeof(0)); // Special case: sizeof size_t.
+ sum += sizeof(void*);
+ sum += sizeof(void const *);
+ sum += sizeof(void const *) / 4;
+ sum += sizeof(str);
+ sum += sizeof(str) / sizeof(char);
+ sum += sizeof(str) / sizeof(str[0]);
+ sum += sizeof(ptr) / sizeof(ptr[0]);
+ sum += sizeof(ptr) / sizeof(*(ptr));
+ return sum;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-constructor.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-constructor.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-constructor.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy %s bugprone-string-constructor %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C> >
+struct basic_string {
+ basic_string();
+ basic_string(const C*, unsigned int size);
+ basic_string(const C *, const A &allocator = A());
+ basic_string(unsigned int size, C c);
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+const char* kText = "";
+const char kText2[] = "";
+extern const char kText3[];
+
+void Test() {
+ std::string str('x', 4);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: string constructor parameters are probably swapped; expecting string(count, character) [bugprone-string-constructor]
+ // CHECK-FIXES: std::string str(4, 'x');
+ std::wstring wstr(L'x', 4);
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: string constructor parameters are probably swapped
+ // CHECK-FIXES: std::wstring wstr(4, L'x');
+ std::string s0(0, 'x');
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string
+ std::string s1(-4, 'x');
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter
+ std::string s2(0x1000000, 'x');
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+
+ std::string q0("test", 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string
+ std::string q1(kText, -4);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter
+ std::string q2("test", 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string literal size
+ std::string q3(kText, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string literal size
+ std::string q4(kText2, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string literal size
+ std::string q5(kText3, 0x1000000);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+ std::string q6(nullptr);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr is undefined behaviour
+ std::string q7 = 0;
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr is undefined behaviour
+}
+
+std::string StringFromZero() {
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour
+}
+
+void Valid() {
+ std::string empty();
+ std::string str(4, 'x');
+ std::wstring wstr(4, L'x');
+ std::string s1("test", 4);
+ std::string s2("test", 3);
+ std::string s3("test");
+}
+
+namespace instantiation_dependent_exprs {
+template<typename T>
+struct S {
+ bool x;
+ std::string f() { return x ? "a" : "b"; }
+};
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-integer-assignment.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-integer-assignment.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-integer-assignment.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-integer-assignment.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,109 @@
+// RUN: %check_clang_tidy %s bugprone-string-integer-assignment %t
+
+namespace std {
+template<typename T>
+struct basic_string {
+ basic_string& operator=(T);
+ basic_string& operator=(basic_string);
+ basic_string& operator+=(T);
+ basic_string& operator+=(basic_string);
+ const T &operator[](int i) const;
+ T &operator[](int i);
+};
+
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+
+int tolower(int i);
+int toupper(int i);
+}
+
+int tolower(int i);
+int toupper(int i);
+
+typedef int MyArcaneChar;
+
+constexpr char kCharConstant = 'a';
+
+int main() {
+ std::string s;
+ std::wstring ws;
+ int x = 5;
+ const char c = 'c';
+
+ s = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [bugprone-string-integer-assignment]
+// CHECK-FIXES: {{^}} s = '6';{{$}}
+ s = 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = "66";{{$}}
+ s = x;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = std::to_string(x);{{$}}
+ s = 'c';
+ s = static_cast<char>(6);
+
+// +=
+ ws += 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L'6';{{$}}
+ ws += 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L"66";{{$}}
+ ws += x;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += std::to_wstring(x);{{$}}
+ ws += L'c';
+ ws += (wchar_t)6;
+
+ std::basic_string<MyArcaneChar> as;
+ as = 6;
+ as = static_cast<MyArcaneChar>(6);
+ as = 'a';
+
+ s += toupper(x);
+ s += tolower(x);
+ s += (std::tolower(x));
+
+ s += c & s[1];
+ s += c ^ s[1];
+ s += c | s[1];
+
+ s[x] += 1;
+ s += s[x];
+ as += as[x];
+
+ // Likely character expressions.
+ s += x & 0xff;
+ s += 0xff & x;
+ s += x % 26;
+ s += 26 % x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+ // CHECK-FIXES: {{^}} s += std::to_string(26 % x);{{$}}
+ s += c | 0x80;
+ s += c | 0x8000;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+ // CHECK-FIXES: {{^}} s += std::to_string(c | 0x8000);{{$}}
+ as += c | 0x8000;
+
+ s += 'a' + (x % 26);
+ s += kCharConstant + (x % 26);
+ s += 'a' + (s[x] & 0xf);
+ s += (x % 10) + 'b';
+
+ s += x > 255 ? c : x;
+ s += x > 255 ? 12 : x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+ // CHECK-FIXES: {{^}} s += std::to_string(x > 255 ? 12 : x);{{$}}
+}
+
+namespace instantiation_dependent_exprs {
+template<typename T>
+struct S {
+ static constexpr T t = 0x8000;
+ std::string s;
+ void f(char c) { s += c | static_cast<int>(t); }
+};
+
+template S<int>;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-literal-with-embedded-nul.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-literal-with-embedded-nul.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-literal-with-embedded-nul.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-string-literal-with-embedded-nul.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,85 @@
+// RUN: %check_clang_tidy %s bugprone-string-literal-with-embedded-nul %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T, typename A>
+struct basic_string {
+ typedef basic_string<C, T, A> _Type;
+ basic_string();
+ basic_string(const C *p, const A &a = A());
+
+ _Type& operator+=(const C* s);
+ _Type& operator=(const C* s);
+};
+
+typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
+typedef basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>> wstring;
+}
+
+bool operator==(const std::string&, const char*);
+bool operator==(const char*, const std::string&);
+
+
+const char Valid[] = "This is valid \x12.";
+const char Strange[] = "This is strange \0x12 and must be fixed";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: suspicious embedded NUL character [bugprone-string-literal-with-embedded-nul]
+
+const char textA[] = "\0x01\0x02\0x03\0x04";
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious embedded NUL character
+const wchar_t textW[] = L"\0x01\0x02\0x03\0x04";
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious embedded NUL character
+
+const char A[] = "\0";
+const char B[] = "\0x";
+const char C[] = "\0x1";
+const char D[] = "\0x11";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
+
+const wchar_t E[] = L"\0";
+const wchar_t F[] = L"\0x";
+const wchar_t G[] = L"\0x1";
+const wchar_t H[] = L"\0x11";
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious embedded NUL character
+
+const char I[] = "\000\000\000\000";
+const char J[] = "\0\0\0\0\0\0";
+const char K[] = "";
+
+const char L[] = "\0x12" "\0x12" "\0x12" "\0x12";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
+
+void TestA() {
+ std::string str1 = "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
+ std::string str2 = "\0";
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
+ std::string str3("\0");
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
+ std::string str4{"\x00\x01\x02\x03"};
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
+
+ std::string str;
+ str += "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: truncated string literal
+ str = "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: truncated string literal
+
+ if (str == "abc\0def") return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: truncated string literal
+ if ("abc\0def" == str) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: truncated string literal
+}
+
+void TestW() {
+ std::wstring str1 = L"abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
+ std::wstring str2 = L"\0";
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
+ std::wstring str3(L"\0");
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
+ std::wstring str4{L"\x00\x01\x02\x03"};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage-strict.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage-strict.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage-strict.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage-strict.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: bugprone-suspicious-enum-usage.StrictMode, value: 1}]}" --
+
+enum A {
+ A = 1,
+ B = 2,
+ C = 4,
+ D = 8,
+ E = 16,
+ F = 32,
+ G = 63
+};
+
+// CHECK-NOTES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but a literal is not power-of-2
+// CHECK-NOTES: :76:7: note: used here as a bitmask
+enum X {
+ X = 8,
+ Y = 16,
+ Z = 4,
+ ZZ = 3
+ // CHECK-NOTES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2 [bugprone-suspicious-enum-usage]
+// CHECK-NOTES: :70:13: note: used here as a bitmask
+};
+// CHECK-NOTES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but some literals are not power-of-2
+// CHECK-NOTES: :73:8: note: used here as a bitmask
+enum PP {
+ P = 2,
+ Q = 3,
+ // CHECK-NOTES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2
+ // CHECK-NOTES: :65:11: note: used here as a bitmask
+ R = 4,
+ S = 8,
+ T = 16,
+ U = 31
+};
+
+enum {
+ H,
+ I,
+ J,
+ K,
+ L
+};
+
+enum Days {
+ Monday,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday
+};
+
+Days bestDay() {
+ return Friday;
+}
+
+int trigger() {
+ if (bestDay() | A)
+ return 1;
+ // CHECK-NOTES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+ if (I | Y)
+ return 1;
+ // CHECK-NOTES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+ if (P + Q == R)
+ return 1;
+ else if ((S | R) == T)
+ return 1;
+ else
+ int k = ZZ | Z;
+ unsigned p = R;
+ PP pp = Q;
+ p |= pp;
+
+ enum X x = Z;
+ p = x | Z;
+ return 0;
+}
+
+int dont_trigger() {
+ int a = 1, b = 5;
+ int c = a + b;
+ int d = c | H, e = b * a;
+ a = B | C;
+ b = X | Z;
+
+ unsigned bitflag;
+ enum A aa = B;
+ bitflag = aa | C;
+
+ if (Tuesday != Monday + 1 ||
+ Friday - Thursday != 1 ||
+ Sunday + Wednesday == (Sunday | Wednesday))
+ return 1;
+ if (H + I + L == 42)
+ return 1;
+ return 42;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-enum-usage.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,96 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: bugprone-suspicious-enum-usage.StrictMode, value: 0}]}" --
+
+enum Empty {
+};
+
+enum A {
+ A = 1,
+ B = 2,
+ C = 4,
+ D = 8,
+ E = 16,
+ F = 32,
+ G = 63
+};
+
+enum X {
+ X = 8,
+ Y = 16,
+ Z = 4
+};
+
+enum {
+ P = 2,
+ Q = 3,
+ R = 4,
+ S = 8,
+ T = 16
+};
+
+enum {
+ H,
+ I,
+ J,
+ K,
+ L
+};
+
+enum Days {
+ Monday,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday
+};
+
+Days bestDay() {
+ return Friday;
+}
+
+int trigger() {
+ Empty EmptyVal;
+ int emptytest = EmptyVal | B;
+ if (bestDay() | A)
+ return 1;
+ // CHECK-NOTES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+ if (I | Y)
+ return 1;
+ // CHECK-NOTES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+}
+
+int dont_trigger() {
+ unsigned p;
+ p = Q | P;
+
+ if (A + G == E)
+ return 1;
+ else if ((Q | R) == T)
+ return 1;
+ else
+ int k = T | Q;
+
+ Empty EmptyVal;
+ int emptytest = EmptyVal | B;
+
+ int a = 1, b = 5;
+ int c = a + b;
+ int d = c | H, e = b * a;
+ a = B | C;
+ b = X | Z;
+
+ if (Tuesday != Monday + 1 ||
+ Friday - Thursday != 1 ||
+ Sunday + Wednesday == (Sunday | Wednesday))
+ return 1;
+ if (H + I + L == 42)
+ return 1;
+ return 42;
+}
+
+namespace PR34400 {
+enum { E1 = 0 };
+enum { E2 = -1 };
+enum { l = E1 | E2 };
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-memset-usage.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-memset-usage.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-memset-usage.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-memset-usage.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,77 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-memset-usage %t
+
+void *memset(void *, int, __SIZE_TYPE__);
+
+namespace std {
+ using ::memset;
+}
+
+template <typename T>
+void mtempl(int *ptr) {
+ memset(ptr, '0', sizeof(T));
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: memset fill value is char '0', potentially mistaken for int 0 [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(ptr, 0, sizeof(T));
+ memset(ptr, 256, sizeof(T));
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: memset fill value is out of unsigned character range, gets truncated [bugprone-suspicious-memset-usage]
+ memset(0, sizeof(T), 0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(0, 0, sizeof(T));
+ memset(0, sizeof(int), 0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(0, 0, sizeof(int));
+}
+
+void foo(int xsize, int ysize) {
+ int i[5] = {1, 2, 3, 4, 5};
+ char ca[3] = {'a', 'b', 'c'};
+ int *p = i;
+ int l = 5;
+ char z = '1';
+ char *c = &z;
+ int v = 0;
+
+ memset(p, '0', l);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: memset fill value is char '0', potentially mistaken for int 0 [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(p, 0, l);
+
+ memset(p, 0xabcd, l);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: memset fill value is out of unsigned character range, gets truncated [bugprone-suspicious-memset-usage]
+
+ memset(p, sizeof(int), 0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(p, 0, sizeof(int));
+ std::memset(p, sizeof(int), 0x00);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: std::memset(p, 0x00, sizeof(int));
+
+#define M_CHAR_ZERO memset(p, '0', l);
+ M_CHAR_ZERO
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset fill value is char '0', potentially mistaken for int 0 [bugprone-suspicious-memset-usage]
+
+#define M_OUTSIDE_RANGE memset(p, 0xabcd, l);
+ M_OUTSIDE_RANGE
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset fill value is out of unsigned character range, gets truncated [bugprone-suspicious-memset-usage]
+
+#define M_ZERO_LENGTH memset(p, sizeof(int), 0);
+ M_ZERO_LENGTH
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+
+ memset(p, '2', l);
+ memset(p, 0, l);
+ memset(c, '0', 1);
+ memset(ca, '0', sizeof(ca));
+
+ memset(p, 0x00, l);
+ mtempl<int>(p);
+
+ memset(p, sizeof(int), v + 1);
+ memset(p, 0xcd, 1);
+
+ // Don't warn when the fill char and the length are both known to be
+ // zero. No bug is possible.
+ memset(p, 0, v);
+
+ // -1 is clearly not a length by virtue of being negative, so no warning
+ // despite v == 0.
+ memset(p, -1, v);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-missing-comma.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-missing-comma.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-missing-comma.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-missing-comma.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,82 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-missing-comma %t
+
+const char* Cartoons[] = {
+ "Bugs Bunny",
+ "Homer Simpson",
+ "Mickey Mouse",
+ "Bart Simpson",
+ "Charlie Brown" // There is a missing comma here.
+ "Fred Flintstone",
+ "Popeye",
+};
+// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: suspicious string literal, probably missing a comma [bugprone-suspicious-missing-comma]
+
+const wchar_t* Colors[] = {
+ L"Red", L"Yellow", L"Blue", L"Green", L"Purple", L"Rose", L"White", L"Black"
+};
+
+// The following array should not trigger any warnings. There is more than 5
+// elements, but they are all concatenated string literals.
+const char* HttpCommands[] = {
+ "GET / HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /favicon.ico HTTP/1.0\r\n"
+ "header: dummy"
+ "\r\n",
+
+ "GET /index.html-en HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html-fr HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html-es HTTP/1.0\r\n"
+ "\r\n",
+};
+
+// This array is too small to trigger a warning.
+const char* SmallArray[] = {
+ "a" "b", "c"
+};
+
+// Parentheses should be enough to avoid warnings.
+const char* ParentheseArray[] = {
+ ("a" "b"), "c",
+ ("d"
+ "e"
+ "f"),
+ "g", "h", "i", "j", "k", "l"
+};
+
+// Indentation should be enough to avoid warnings.
+const char* CorrectlyIndentedArray[] = {
+ "This is a long message "
+ "which is spanning over multiple lines."
+ "And this should be fine.",
+ "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l"
+};
+
+const char* IncorrectlyIndentedArray[] = {
+ "This is a long message "
+ "which is spanning over multiple lines."
+ "And this should be fine.",
+ "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l"
+};
+// CHECK-MESSAGES: :[[@LINE-6]]:3: warning: suspicious string literal, probably missing a comma [bugprone-suspicious-missing-comma]
+
+const char* TooManyConcatenatedTokensArray[] = {
+ "Dummy line",
+ "Dummy line",
+ "a" "b" "c" "d" "e" "f",
+ "g" "h" "i" "j" "k" "l",
+ "Dummy line",
+ "Dummy line",
+ "Dummy line",
+ "Dummy line",
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon-fail.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon-fail.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon-fail.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon-fail.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,28 @@
+// RUN: not clang-tidy %s \
+// RUN: -checks="-*,bugprone-suspicious-semicolon" -- -DERROR 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ERROR \
+// RUN: -implicit-check-not="{{warning|error}}:"
+// RUN: not clang-tidy %s \
+// RUN: -checks="-*,bugprone-suspicious-semicolon,clang-diagnostic*" \
+// RUN: -- -DWERROR -Wno-everything -Werror=unused-variable 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-WERROR \
+// RUN: -implicit-check-not="{{warning|error}}:"
+
+// Note: This test verifies that, the checker does not emit any warning for
+// files that do not compile.
+
+bool g();
+
+void f() {
+ if (g());
+ // CHECK-WERROR: :[[@LINE-1]]:11: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+#if ERROR
+ int a
+ // CHECK-ERROR: :[[@LINE-1]]:8: error: expected ';' at end of declaration [clang-diagnostic-error]
+#elif WERROR
+ int a;
+ // CHECK-WERROR: :[[@LINE-1]]:7: error: unused variable 'a' [clang-diagnostic-unused-variable]
+#else
+#error "One of ERROR or WERROR should be defined.
+#endif
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-semicolon.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,117 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-semicolon %t
+
+int x = 5;
+
+void nop();
+
+void correct1()
+{
+ if(x < 5) nop();
+}
+
+void correct2()
+{
+ if(x == 5)
+ nop();
+}
+
+void correct3()
+{
+ if(x > 5)
+ {
+ nop();
+ }
+}
+
+void fail1()
+{
+ if(x > 5); nop();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+ // CHECK-FIXES: if(x > 5) nop();
+}
+
+void fail2()
+{
+ if(x == 5);
+ nop();
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+ // CHECK-FIXES: if(x == 5){{$}}
+}
+
+void fail3()
+{
+ if(x < 5);
+ {
+ nop();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: potentially unintended semicolon
+ // CHECK-FIXES: if(x < 5){{$}}
+}
+
+void correct4()
+{
+ while(x % 5 == 1);
+ nop();
+}
+
+void correct5()
+{
+ for(int i = 0; i < x; ++i)
+ ;
+}
+
+void fail4()
+{
+ for(int i = 0; i < x; ++i);
+ nop();
+ // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: potentially unintended semicolon
+ // CHECK-FIXES: for(int i = 0; i < x; ++i){{$}}
+}
+
+void fail5()
+{
+ if(x % 5 == 1);
+ nop();
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: potentially unintended semicolon
+ // CHECK-FIXES: if(x % 5 == 1){{$}}
+}
+
+void fail6() {
+ int a = 0;
+ if (a != 0) {
+ } else if (a != 1);
+ a = 2;
+ // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: potentially unintended semicolon
+ // CHECK-FIXES: } else if (a != 1){{$}}
+}
+
+void fail7() {
+ if (true)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: potentially unintended semicolon
+}
+
+void correct6()
+{
+ do; while(false);
+}
+
+int correct7()
+{
+ int t_num = 0;
+ char c = 'b';
+ char *s = "a";
+ if (s == "(" || s != "'" || c == '"') {
+ t_num += 3;
+ return (c == ')' && c == '\'');
+ }
+
+ return 0;
+}
+
+void correct8() {
+ if (true)
+ ;
+ else {
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,79 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-string-compare %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: bugprone-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \
+// RUN: {key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \
+// RUN: -- -std=c99
+
+static const char A[] = "abc";
+
+int strcmp(const char *, const char *);
+
+int test_warning_patterns() {
+ if (strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [bugprone-suspicious-string-compare]
+ // CHECK-FIXES: if (strcmp(A, "a") != 0)
+
+ if (strcmp(A, "a") != 0 ||
+ strcmp(A, "b"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcmp(A, "b") != 0)
+
+ if (strcmp(A, "a") == 1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") == -1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < '0')
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < 0.)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+
+ if (!strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:8: warning: function 'strcmp' is compared using logical not operator
+ // CHECK-FIXES: if (strcmp(A, "a") == 0)
+}
+
+void test_structure_patterns() {
+ if (strcmp(A, "a")) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: if (strcmp(A, "a") != 0) {}
+
+ while (strcmp(A, "a")) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: while (strcmp(A, "a") != 0) {}
+
+ for (;strcmp(A, "a");) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: for (;strcmp(A, "a") != 0;) {}
+}
+
+int test_valid_patterns() {
+ // The following cases are valid.
+ if (strcmp(A, "a") < 0) return 0;
+ if (strcmp(A, "a") == 0) return 0;
+ if (strcmp(A, "a") <= 0) return 0;
+ if (strcmp(A, "a") == strcmp(A, "b")) return 0;
+ return 1;
+}
+
+int wrapper(const char* a, const char* b) {
+ return strcmp(a, b);
+}
+
+int assignment_wrapper(const char* a, const char* b) {
+ int cmp = strcmp(a, b);
+ return cmp;
+}
+
+int condexpr_wrapper(const char* a, const char* b) {
+ return (a < b) ? strcmp(a, b) : strcmp(b, a);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-suspicious-string-compare.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,337 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-string-compare %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: bugprone-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \
+// RUN: {key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \
+// RUN: --
+
+typedef __SIZE_TYPE__ size;
+
+struct locale_t {
+ void* dummy;
+} locale;
+
+static const char A[] = "abc";
+static const unsigned char U[] = "abc";
+static const unsigned char V[] = "xyz";
+static const wchar_t W[] = L"abc";
+
+int strlen(const char *);
+
+int memcmp(const void *, const void *, size);
+int wmemcmp(const wchar_t *, const wchar_t *, size);
+int memicmp(const void *, const void *, size);
+int _memicmp(const void *, const void *, size);
+int _memicmp_l(const void *, const void *, size, locale_t);
+
+int strcmp(const char *, const char *);
+int strncmp(const char *, const char *, size);
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size);
+int stricmp(const char *, const char *);
+int strcmpi(const char *, const char *);
+int strnicmp(const char *, const char *, size);
+int _stricmp(const char *, const char * );
+int _strnicmp(const char *, const char *, size);
+int _stricmp_l(const char *, const char *, locale_t);
+int _strnicmp_l(const char *, const char *, size, locale_t);
+
+int wcscmp(const wchar_t *, const wchar_t *);
+int wcsncmp(const wchar_t *, const wchar_t *, size);
+int wcscasecmp(const wchar_t *, const wchar_t *);
+int wcsicmp(const wchar_t *, const wchar_t *);
+int wcsnicmp(const wchar_t *, const wchar_t *, size);
+int _wcsicmp(const wchar_t *, const wchar_t *);
+int _wcsnicmp(const wchar_t *, const wchar_t *, size);
+int _wcsicmp_l(const wchar_t *, const wchar_t *, locale_t);
+int _wcsnicmp_l(const wchar_t *, const wchar_t *, size, locale_t);
+
+int _mbscmp(const unsigned char *, const unsigned char *);
+int _mbsncmp(const unsigned char *, const unsigned char *, size);
+int _mbsnbcmp(const unsigned char *, const unsigned char *, size);
+int _mbsnbicmp(const unsigned char *, const unsigned char *, size);
+int _mbsicmp(const unsigned char *, const unsigned char *);
+int _mbsnicmp(const unsigned char *, const unsigned char *, size);
+int _mbscmp_l(const unsigned char *, const unsigned char *, locale_t);
+int _mbsncmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsicmp_l(const unsigned char *, const unsigned char *, locale_t);
+int _mbsnicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsnbcmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsnbicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+
+int test_warning_patterns() {
+ if (strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [bugprone-suspicious-string-compare]
+ // CHECK-FIXES: if (strcmp(A, "a") != 0)
+
+ if (strcmp(A, "a") == 0 ||
+ strcmp(A, "b"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcmp(A, "b") != 0)
+
+ if (strcmp(A, "a") == 1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") == -1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") == true)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < '0')
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < 0.)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+}
+
+int test_valid_patterns() {
+ // The following cases are valid.
+ if (strcmp(A, "a") < 0)
+ return 0;
+ if (strcmp(A, "a") == 0)
+ return 0;
+ if (strcmp(A, "a") <= 0)
+ return 0;
+
+ if (wcscmp(W, L"a") < 0)
+ return 0;
+ if (wcscmp(W, L"a") == 0)
+ return 0;
+ if (wcscmp(W, L"a") <= 0)
+ return 0;
+
+ return 1;
+}
+
+int test_implicit_compare_with_functions() {
+
+ if (memcmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memcmp' is called without explicitly comparing result
+ // CHECK-FIXES: memcmp(A, "a", 1) != 0)
+
+ if (wmemcmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wmemcmp' is called without explicitly comparing result
+ // CHECK-FIXES: wmemcmp(W, L"a", 1) != 0)
+
+ if (memicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memicmp' is called without explicitly comparing result
+ // CHECK-FIXES: memicmp(A, "a", 1) != 0)
+
+ if (_memicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _memicmp(A, "a", 1) != 0)
+
+ if (_memicmp_l(A, "a", 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _memicmp_l(A, "a", 1, locale) != 0)
+
+ if (strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcmp(A, "a") != 0)
+
+ if (strncmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncmp' is called without explicitly comparing result
+ // CHECK-FIXES: strncmp(A, "a", 1) != 0)
+
+ if (strcasecmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcasecmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcasecmp(A, "a") != 0)
+
+ if (strncasecmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncasecmp' is called without explicitly comparing result
+ // CHECK-FIXES: strncasecmp(A, "a", 1) != 0)
+
+ if (stricmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'stricmp' is called without explicitly comparing result
+ // CHECK-FIXES: stricmp(A, "a") != 0)
+
+ if (strcmpi(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmpi' is called without explicitly comparing result
+ // CHECK-FIXES: strcmpi(A, "a") != 0)
+
+ if (_stricmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp' is called without explicitly comparing result
+ // CHECK-FIXES: _stricmp(A, "a") != 0)
+
+ if (strnicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: strnicmp(A, "a", 1) != 0)
+
+ if (_strnicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _strnicmp(A, "a", 1) != 0)
+
+ if (_stricmp_l(A, "a", locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _stricmp_l(A, "a", locale) != 0)
+
+ if (_strnicmp_l(A, "a", 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _strnicmp_l(A, "a", 1, locale) != 0)
+
+ if (wcscmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcscmp(W, L"a") != 0)
+
+ if (wcsncmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsncmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcsncmp(W, L"a", 1) != 0)
+
+ if (wcscasecmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscasecmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcscasecmp(W, L"a") != 0)
+
+ if (wcsicmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsicmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcsicmp(W, L"a") != 0)
+
+ if (_wcsicmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsicmp(W, L"a") != 0)
+
+ if (_wcsicmp_l(W, L"a", locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsicmp_l(W, L"a", locale) != 0)
+
+ if (wcsnicmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcsnicmp(W, L"a", 1) != 0)
+
+ if (_wcsnicmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsnicmp(W, L"a", 1) != 0)
+
+ if (_wcsnicmp_l(W, L"a", 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsnicmp_l(W, L"a", 1, locale) != 0)
+
+ if (_mbscmp(U, V))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbscmp(U, V) != 0)
+
+ if (_mbsncmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsncmp(U, V, 1) != 0)
+
+ if (_mbsnbcmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbcmp(U, V, 1) != 0)
+
+ if (_mbsnbicmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbicmp(U, V, 1) != 0)
+
+ if (_mbsicmp(U, V))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsicmp(U, V) != 0)
+
+ if (_mbsnicmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnicmp(U, V, 1) != 0)
+
+ if (_mbscmp_l(U, V, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbscmp_l(U, V, locale) != 0)
+
+ if (_mbsncmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsncmp_l(U, V, 1, locale) != 0)
+
+ if (_mbsicmp_l(U, V, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsicmp_l(U, V, locale) != 0)
+
+ if (_mbsnicmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnicmp_l(U, V, 1, locale) != 0)
+
+ if (_mbsnbcmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbcmp_l(U, V, 1, locale) != 0)
+
+ if (_mbsnbicmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbicmp_l(U, V, 1, locale) != 0)
+
+ return 1;
+}
+
+int strcmp_wrapper1(const char* a, const char* b) {
+ return strcmp(a, b);
+}
+
+int strcmp_wrapper2(const char* a, const char* b) {
+ return (a && b) ? strcmp(a, b) : 0;
+}
+
+#define macro_strncmp(s1, s2, n) \
+ (__extension__ (__builtin_constant_p (n) \
+ && ((__builtin_constant_p (s1) \
+ && strlen (s1) < ((size) (n))) \
+ || (__builtin_constant_p (s2) \
+ && strlen (s2) < ((size) (n)))) \
+ ? strcmp (s1, s2) : strncmp (s1, s2, n)))
+
+int strncmp_macro(const char* a, const char* b) {
+ if (macro_strncmp(a, b, 4))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+
+ if (macro_strncmp(a, b, 4) == 2)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (macro_strncmp(a, b, 4) <= .0)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+
+ if (macro_strncmp(a, b, 4) + 0)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: results of function 'strcmp' used by operator '+'
+
+ return 1;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-swapped-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-swapped-arguments.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-swapped-arguments.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-swapped-arguments.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,53 @@
+// RUN: %check_clang_tidy %s bugprone-swapped-arguments %t
+
+void F(int, double);
+
+int SomeFunction();
+
+template <typename T, typename U>
+void G(T a, U b) {
+ F(a, b); // no-warning
+ F(2.0, 4);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: F(4, 2.0)
+}
+
+void foo() {
+ F(1.0, 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: F(3, 1.0)
+
+#define M(x, y) x##y()
+
+ double b = 1.0;
+ F(b, M(Some, Function));
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: F(M(Some, Function), b);
+
+#define N F(b, SomeFunction())
+
+ N;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// In macro, don't emit fixits.
+// CHECK-FIXES: #define N F(b, SomeFunction())
+
+ G(b, 3);
+ G(3, 1.0);
+ G(0, 0);
+
+ F(1.0, 1.0); // no-warning
+ F(3, 1.0); // no-warning
+ F(true, false); // no-warning
+ F(0, 'c'); // no-warning
+
+#define APPLY(f, x, y) f(x, y)
+ APPLY(F, 1.0, 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: APPLY(F, 3, 1.0);
+
+#define PARAMS 1.0, 3
+#define CALL(P) F(P)
+ CALL(PARAMS);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// In macro, don't emit fixits.
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-terminating-continue.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-terminating-continue.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-terminating-continue.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-terminating-continue.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,65 @@
+// RUN: %check_clang_tidy %s bugprone-terminating-continue %t
+
+void f() {
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(false);
+
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(0);
+
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(nullptr);
+
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(__null);
+
+
+ do {
+ int x = 1;
+ if (x > 0) continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: if (x > 0) break;
+ } while (false);
+}
+
+void g() {
+ do {
+ do {
+ continue;
+ int x = 1;
+ } while (1 == 1);
+ } while (false);
+
+ do {
+ for (int i = 0; i < 1; ++i) {
+ continue;
+ int x = 1;
+ }
+ } while (false);
+
+ do {
+ while (true) {
+ continue;
+ int x = 1;
+ }
+ } while (false);
+
+ int v[] = {1,2,3,34};
+ do {
+ for (int n : v) {
+ if (n>2) continue;
+ }
+ } while (false);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-throw-keyword-missing.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,167 @@
+// RUN: %check_clang_tidy %s bugprone-throw-keyword-missing %t -- -- -fexceptions
+
+namespace std {
+
+// std::string declaration (taken from test/clang-tidy/readability-redundant-string-cstr-msvc.cpp).
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>>
+struct basic_string {
+ basic_string();
+ basic_string(const basic_string &);
+ // MSVC headers define two constructors instead of using optional arguments.
+ basic_string(const C *);
+ basic_string(const C *, const A &);
+ ~basic_string();
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+
+// std::exception and std::runtime_error declaration.
+struct exception {
+ exception();
+ exception(const exception &other);
+ virtual ~exception();
+};
+
+struct runtime_error : public exception {
+ explicit runtime_error(const std::string &what_arg);
+};
+
+} // namespace std
+
+// The usage of this class should never emit a warning.
+struct RegularClass {};
+
+// Class name contains the substring "exception", in certain cases using this class should emit a warning.
+struct RegularException {
+ RegularException() {}
+
+ // Constructors with a single argument are treated differently (cxxFunctionalCastExpr).
+ RegularException(int) {}
+};
+
+// --------------
+
+void stdExceptionNotTrownTest(int i) {
+ if (i < 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception object created but not thrown; did you mean 'throw {{.*}}'? [bugprone-throw-keyword-missing]
+ std::exception();
+
+ if (i > 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ std::runtime_error("Unexpected argument");
+}
+
+void stdExceptionThrownTest(int i) {
+ if (i < 0)
+ throw std::exception();
+
+ if (i > 0)
+ throw std::runtime_error("Unexpected argument");
+}
+
+void regularClassNotThrownTest(int i) {
+ if (i < 0)
+ RegularClass();
+}
+
+void regularClassThrownTest(int i) {
+ if (i < 0)
+ throw RegularClass();
+}
+
+void nameContainsExceptionNotThrownTest(int i) {
+ if (i < 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ RegularException();
+
+ if (i > 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ RegularException(5);
+}
+
+void nameContainsExceptionThrownTest(int i) {
+ if (i < 0)
+ throw RegularException();
+
+ if (i > 0)
+ throw RegularException(5);
+}
+
+template <class Exception>
+void f(int i, Exception excToBeThrown) {}
+
+void funcCallWithTempExcTest() {
+ f(5, RegularException());
+}
+
+// Global variable initilization test.
+RegularException exc = RegularException();
+RegularException *excptr = new RegularException();
+
+void localVariableInitTest() {
+ RegularException exc = RegularException();
+ RegularException *excptr = new RegularException();
+}
+
+class CtorInitializerListTest {
+ RegularException exc;
+
+ CtorInitializerListTest() : exc(RegularException()) {}
+
+ CtorInitializerListTest(int) try : exc(RegularException()) {
+ // Constructor body
+ } catch (...) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ RegularException();
+ }
+
+ CtorInitializerListTest(float);
+};
+
+CtorInitializerListTest::CtorInitializerListTest(float) try : exc(RegularException()) {
+ // Constructor body
+} catch (...) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: suspicious exception
+ RegularException();
+}
+
+RegularException funcReturningExceptionTest(int i) {
+ return RegularException();
+}
+
+void returnedValueTest() {
+ funcReturningExceptionTest(3);
+}
+
+struct ClassBracedInitListTest {
+ ClassBracedInitListTest(RegularException exc) {}
+};
+
+void foo(RegularException, ClassBracedInitListTest) {}
+
+void bracedInitListTest() {
+ RegularException exc{};
+ ClassBracedInitListTest test = {RegularException()};
+ foo({}, {RegularException()});
+}
+
+typedef std::exception ERROR_BASE;
+class RegularError : public ERROR_BASE {};
+
+void typedefTest() {
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: suspicious exception
+ RegularError();
+}
+
+struct ExceptionRAII {
+ ExceptionRAII() {}
+ ~ExceptionRAII() {}
+};
+
+void exceptionRAIITest() {
+ ExceptionRAII E;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable-magniute-bits-upper-limit.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable-magniute-bits-upper-limit.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable-magniute-bits-upper-limit.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable-magniute-bits-upper-limit.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy %s bugprone-too-small-loop-variable %t -- -- --target=x86_64-linux
+
+// MagnitudeBitsUpperLimit = 16 (default value)
+
+unsigned long size() { return 294967296l; }
+
+void voidFilteredOutForLoop1() {
+ for (long i = 0; i < size(); ++i) {
+ // no warning
+ }
+}
+
+void voidCaughtForLoop1() {
+ for (int i = 0; i < size(); ++i) {
+ // no warning
+ }
+}
+
+void voidCaughtForLoop2() {
+ for (short i = 0; i < size(); ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'unsigned long' [bugprone-too-small-loop-variable]
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-too-small-loop-variable.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,255 @@
+// RUN: %check_clang_tidy %s bugprone-too-small-loop-variable %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit, \
+// RUN: value: 1024}]}" \
+// RUN: -- --target=x86_64-linux
+
+long size() { return 294967296l; }
+
+////////////////////////////////////////////////////////////////////////////////
+/// Test cases correctly caught by bugprone-too-small-loop-variable.
+
+void voidBadForLoop() {
+ for (int i = 0; i < size(); ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidBadForLoop2() {
+ for (int i = 0; i < size() + 10; ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidBadForLoop3() {
+ for (int i = 0; i <= size() - 1; ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidBadForLoop4() {
+ for (int i = 0; size() > i; ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidBadForLoop5() {
+ for (int i = 0; size() - 1 >= i; ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidBadForLoop6() {
+ int i = 0;
+ for (; i < size(); ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidForLoopUnsignedBound() {
+ unsigned size = 3147483647;
+ for (int i = 0; i < size; ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'unsigned int' [bugprone-too-small-loop-variable]
+ }
+}
+
+// The iteration's upper bound has a template dependent value.
+template <long size>
+void doSomething() {
+ for (short i = 0; i < size; ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+// The iteration's upper bound has a template dependent type.
+template <class T>
+void doSomething() {
+ for (T i = 0; i < size(); ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidForLoopInstantiation() {
+ // This line does not trigger the warning.
+ doSomething<long>();
+ // This one triggers the warning.
+ doSomething<short>();
+}
+
+// A suspicious function used in a macro.
+#define SUSPICIOUS_SIZE (size())
+void voidBadForLoopWithMacroBound() {
+ for (short i = 0; i < SUSPICIOUS_SIZE; ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Correct loops: we should not warn here.
+
+// A simple use case when both expressions have the same type.
+void voidGoodForLoop() {
+ for (long i = 0; i < size(); ++i) { // no warning
+ }
+}
+
+// Other use case where both expressions have the same type,
+// but short expressions are converted to int by the compare operator.
+void voidGoodForLoop2() {
+ short loopCond = 10;
+ for (short i = 0; i < loopCond; ++i) { // no warning
+ }
+}
+
+// Because of the integer literal, the iteration's upper bound is int, but we suppress the warning here.
+void voidForLoopShortPlusLiteral() {
+ short size = 30000;
+ for (short i = 0; i <= (size - 1); ++i) { // no warning
+ }
+}
+
+// Addition of two short variables results in an int value, but we suppress this to avoid false positives.
+void voidForLoopShortPlusShort() {
+ short size = 256;
+ short increment = 14;
+ for (short i = 0; i < size + increment; ++i) { // no warning
+ }
+}
+
+// In this test case we have different integer types, but here the loop variable has the bigger type.
+// The iteration's bound is cast implicitly, not the loop variable.
+void voidForLoopBoundImplicitCast() {
+ short start = 256;
+ short end = 14;
+ for (int i = start; i >= end; --i) { // no warning
+ }
+}
+
+// Range based loop and other iterator based loops are ignored by this check.
+void voidRangeBasedForLoop() {
+ int array[] = {1, 2, 3, 4, 5};
+ for (const int &i : array) { // no warning
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Future possibilites to improve the check.
+
+// False positive: because of the int literal, iteration's upper bound has int type.
+void voidForLoopFalsePositive() {
+ short size = 30000;
+ bool cond = false;
+ for (short i = 0; i < (cond ? 0 : size); ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]
+ }
+}
+
+void voidForLoopFalsePositive2() {
+ short size = 30000;
+ bool cond = false;
+ for (short i = 0; i < (!cond ? size : 0); ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]
+ }
+}
+
+// False positive: The loop bound expression contains nested binary operators.
+void voidForLoopFalsePositive3() {
+ short number = 30000;
+ for (short i = 0; i < ((number & 0x7f) + 1); ++i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]
+ }
+}
+
+// TODO: handle while loop.
+void voidBadWhileLoop() {
+ short i = 0;
+ while (i < size()) { // missing warning
+ ++i;
+ }
+}
+
+// TODO: handle do-while loop.
+void voidBadDoWhileLoop() {
+ short i = 0;
+ do {
+ ++i;
+ } while (i < size()); // missing warning
+}
+
+// TODO: handle complex loop conditions.
+void voidComplexForCond() {
+ bool additionalCond = true;
+ for (int i = 0; i < size() && additionalCond; ++i) { // missing warning
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Suspicious test cases ingored by this check.
+
+// Test case with a reverse iteration.
+// This is caught by -Wimplicit-int-conversion.
+void voidReverseForLoop() {
+ for (short i = size() - 1; i >= 0; --i) { // no warning
+ }
+}
+
+// Macro defined literals are used inside the loop condition.
+#define SIZE 125
+#define SIZE2 (SIZE + 1)
+void voidForLoopWithMacroBound() {
+ for (short i = 0; i < SIZE2; ++i) { // no warning
+ }
+}
+
+// A suspicious loop is not caught if the iteration's upper bound is a literal.
+void voidForLoopWithLiteralBound() {
+ for (short i = 0; i < 125; ++i) { // no warning
+ }
+}
+
+// The used literal leads to an infinite loop.
+// This is caught by -Wtautological-constant-out-of-range-compare.
+void voidForLoopWithBigLiteralBound() {
+ for (short i = 0; i < 294967296l; ++i) { // no warning
+ }
+}
+
+enum eSizeType {
+ START,
+ Y,
+ END
+};
+
+// A suspicious loop is not caught if the iteration's upper bound is an enum value.
+void voidForLoopWithEnumBound() {
+ for (short i = eSizeType::START; i < eSizeType::END; ++i) { // no warning
+ }
+}
+
+enum eSizeType2 : long {
+ START2 = 294967296l,
+ Y2,
+ END2
+};
+
+// The used enum value leads to an infinite loop.
+// This is caught by -Wtautological-constant-out-of-range-compare.
+void voidForLoopWithBigEnumBound() {
+ for (short i = eSizeType2::START2; i < eSizeType2::END2; ++i) { // no warning
+ }
+}
+
+// A suspicious loop is not caught if the iteration's upper bound is a constant variable.
+void voidForLoopWithConstBound() {
+ const long size = 252l;
+ for (short i = 0; i < size; ++i) { // no warning
+ }
+}
+
+// The used constant variable leads to an infinite loop.
+// This is caught by -Wtautological-constant-out-of-range-compare.
+void voidForLoopWithBigConstBound() {
+ const long size = 294967296l;
+ for (short i = 0; i < size; ++i) { // no warning
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undefined-memory-manipulation.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,213 @@
+// RUN: %check_clang_tidy %s bugprone-undefined-memory-manipulation %t
+
+void *memset(void *, int, __SIZE_TYPE__);
+void *memcpy(void *, const void *, __SIZE_TYPE__);
+void *memmove(void *, const void *, __SIZE_TYPE__);
+
+namespace std {
+using ::memcpy;
+using ::memmove;
+using ::memset;
+}
+
+namespace types {
+// TriviallyCopyable types:
+struct Plain {
+ int n;
+};
+
+enum E {
+ X,
+ Y,
+ Z
+};
+
+struct Base {
+ float b;
+};
+
+struct Derived : Base {
+ bool d;
+};
+
+// not TriviallyCopyable types:
+struct Destruct {
+ ~Destruct() {}
+};
+
+struct Copy {
+ Copy() {}
+ Copy(const Copy &) {}
+};
+
+struct Move {
+ Move() {}
+ Move(Move &&) {}
+};
+
+struct VirtualFunc {
+ virtual void f() {}
+};
+
+struct VirtualBase : virtual Base {
+ int vb;
+};
+
+// Incomplete type, assume it is TriviallyCopyable.
+struct NoDef;
+
+} // end namespace types
+
+void f(types::NoDef *s) {
+ memset(s, 0, 5);
+}
+
+template <typename T>
+void memset_temp(T *b) {
+ memset(b, 0, sizeof(T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' is not TriviallyCopyable [bugprone-undefined-memory-manipulation]
+}
+
+template <typename S, typename T>
+void memcpy_temp(S *a, T *b) {
+ memcpy(a, b, sizeof(T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
+}
+
+template <typename S, typename T>
+void memmove_temp(S *a, T *b) {
+ memmove(a, b, sizeof(T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
+}
+
+namespace aliases {
+using Copy2 = types::Copy;
+typedef types::Move Move2;
+}
+
+void notTriviallyCopyable() {
+ types::Plain p; // TriviallyCopyable for variety
+ types::Destruct d;
+ types::Copy c;
+ types::Move m;
+ types::VirtualFunc vf;
+ types::VirtualBase vb;
+
+ memset(&vf, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
+ memset(&d, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
+ memset(&c, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy'
+ std::memset(&m, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move'
+ ::memset(&vb, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase'
+
+ memcpy(&p, &vf, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
+ memcpy(&p, &d, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Destruct'
+ memcpy(&c, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy'
+ std::memcpy(&m, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move'
+ ::memcpy(&vb, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase'
+
+ memmove(&vf, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
+ memmove(&d, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
+ memmove(&p, &c, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy'
+ std::memmove(&p, &m, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Move'
+ ::memmove(&p, &vb, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualBase'
+
+#define MEMSET memset(&vf, 0, sizeof(int));
+ MEMSET
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
+#define MEMCPY memcpy(&d, &p, sizeof(int));
+ MEMCPY
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
+#define MEMMOVE memmove(&p, &c, sizeof(int));
+ MEMMOVE
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy'
+
+ memset_temp<types::VirtualFunc>(&vf);
+ memcpy_temp<types::Plain, types::VirtualFunc>(&p, &vf);
+ memmove_temp<types::Plain, types::VirtualFunc>(&p, &vf);
+
+ aliases::Copy2 c2;
+ aliases::Move2 m2;
+ memset(&c2, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
+ memset(&m2, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Move2'
+
+ typedef aliases::Copy2 Copy3;
+ typedef aliases::Copy2 *PCopy2;
+ typedef Copy3 *PCopy3;
+ Copy3 c3;
+ PCopy2 pc2;
+ PCopy3 pc3;
+ memset(&c3, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
+ memset(pc2, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
+ memset(pc3, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
+}
+
+void triviallyCopyable() {
+ types::Plain p;
+ types::Base base;
+ types::Derived derived;
+
+ int i = 5;
+ int ia[3] = {1, 2, 3};
+ float f = 3.14;
+ float fa[3] = {1.1, 2.2, 3.3};
+ bool b = false;
+ bool ba[2] = {true, false};
+ types::E e = types::X;
+ p.n = 2;
+
+ memset(&p, 0, sizeof(int));
+ memset(&base, 0, sizeof(float));
+ memset(&derived, 0, sizeof(bool));
+ memset(&i, 0, sizeof(int));
+ memset(ia, 0, sizeof(int));
+ memset(&f, 0, sizeof(float));
+ memset(fa, 0, sizeof(float));
+ memset(&b, 0, sizeof(bool));
+ memset(ba, 0, sizeof(bool));
+ memset(&e, 0, sizeof(int));
+ memset(&p.n, 0, sizeof(int));
+
+ memcpy(&p, &p, sizeof(int));
+ memcpy(&base, &base, sizeof(float));
+ memcpy(&derived, &derived, sizeof(bool));
+ memcpy(&i, &i, sizeof(int));
+ memcpy(ia, ia, sizeof(int));
+ memcpy(&f, &f, sizeof(float));
+ memcpy(fa, fa, sizeof(float));
+ memcpy(&b, &b, sizeof(bool));
+ memcpy(ba, ba, sizeof(bool));
+ memcpy(&e, &e, sizeof(int));
+ memcpy(&p.n, &p.n, sizeof(int));
+
+ memmove(&p, &p, sizeof(int));
+ memmove(&base, &base, sizeof(float));
+ memmove(&derived, &derived, sizeof(bool));
+ memmove(&i, &i, sizeof(int));
+ memmove(ia, ia, sizeof(int));
+ memmove(&f, &f, sizeof(float));
+ memmove(fa, fa, sizeof(float));
+ memmove(&b, &b, sizeof(bool));
+ memmove(ba, ba, sizeof(bool));
+ memmove(&e, &e, sizeof(int));
+ memmove(&p.n, &p.n, sizeof(int));
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor-cxx98.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor-cxx98.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor-cxx98.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor-cxx98.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,23 @@
+// RUN: clang-tidy %s -checks=-*,bugprone-undelegated-constructor -- -std=c++98 | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+struct Ctor;
+Ctor foo();
+
+struct Ctor {
+ Ctor();
+ Ctor(int);
+ Ctor(int, int);
+ Ctor(Ctor *i) {
+ Ctor();
+ Ctor(0);
+ Ctor(1, 2);
+ foo();
+ }
+};
+
+Ctor::Ctor() {
+ Ctor(1);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-undelegated-constructor.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,54 @@
+// RUN: %check_clang_tidy %s bugprone-undelegated-constructor %t
+
+struct Ctor;
+Ctor foo();
+
+struct Ctor {
+ Ctor();
+ Ctor(int);
+ Ctor(int, int);
+ Ctor(Ctor *i) {
+ Ctor();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead [bugprone-undelegated-constructor]
+ Ctor(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ Ctor(1, 2);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ foo();
+ }
+};
+
+Ctor::Ctor() {
+ Ctor(1);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: did you intend to call a delegated constructor?
+}
+
+Ctor::Ctor(int i) : Ctor(i, 1) {} // properly delegated.
+
+struct Dtor {
+ Dtor();
+ Dtor(int);
+ Dtor(int, int);
+ Dtor(Ctor *i) {
+ Dtor();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ Dtor(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ Dtor(1, 2);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ }
+ ~Dtor();
+};
+
+struct Base {};
+struct Derived : public Base {
+ Derived() { Base(); }
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: did you intend to call a delegated constructor?
+};
+
+template <typename T>
+struct TDerived : public Base {
+ TDerived() { Base(); }
+};
+
+TDerived<int> t;
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment-warn-only-if-this-has-suspicious-field.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment-warn-only-if-this-has-suspicious-field.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment-warn-only-if-this-has-suspicious-field.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment-warn-only-if-this-has-suspicious-field.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s bugprone-unhandled-self-assignment %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField, \
+// RUN: value: 0}]}"
+
+// Classes with pointer field are still caught.
+class PtrField {
+public:
+ PtrField &operator=(const PtrField &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// With the option, check catches classes with trivial fields.
+class TrivialFields {
+public:
+ TrivialFields &operator=(const TrivialFields &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ return *this;
+ }
+
+private:
+ int m;
+ float f;
+ double d;
+ bool b;
+};
+
+// The check warns also when there is no field at all.
+// In this case, user-defined copy assignment operator is useless anyway.
+class ClassWithoutFields {
+public:
+ ClassWithoutFields &operator=(const ClassWithoutFields &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ return *this;
+ }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unhandled-self-assignment.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,579 @@
+// RUN: %check_clang_tidy %s bugprone-unhandled-self-assignment %t -- -- -fno-delayed-template-parsing
+
+namespace std {
+
+template <class T>
+void swap(T x, T y) {
+}
+
+template <class T>
+T &&move(T x) {
+}
+
+template <class T>
+class unique_ptr {
+};
+
+template <class T>
+class shared_ptr {
+};
+
+template <class T>
+class weak_ptr {
+};
+
+template <class T>
+class auto_ptr {
+};
+
+} // namespace std
+
+void assert(int expression){};
+
+///////////////////////////////////////////////////////////////////
+/// Test cases correctly caught by the check.
+
+class PtrField {
+public:
+ PtrField &operator=(const PtrField &object);
+
+private:
+ int *p;
+};
+
+PtrField &PtrField::operator=(const PtrField &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+}
+
+// Class with an inline operator definition.
+class InlineDefinition {
+public:
+ InlineDefinition &operator=(const InlineDefinition &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+class UniquePtrField {
+public:
+ UniquePtrField &operator=(const UniquePtrField &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ std::unique_ptr<int> p;
+};
+
+class SharedPtrField {
+public:
+ SharedPtrField &operator=(const SharedPtrField &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ std::shared_ptr<int> p;
+};
+
+class WeakPtrField {
+public:
+ WeakPtrField &operator=(const WeakPtrField &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ std::weak_ptr<int> p;
+};
+
+class AutoPtrField {
+public:
+ AutoPtrField &operator=(const AutoPtrField &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ std::auto_ptr<int> p;
+};
+
+// Class with C array field.
+class CArrayField {
+public:
+ CArrayField &operator=(const CArrayField &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ int array[256];
+};
+
+// Make sure to not ignore cases when the operator definition calls
+// a copy constructor of another class.
+class CopyConstruct {
+public:
+ CopyConstruct &operator=(const CopyConstruct &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ WeakPtrField a;
+ WeakPtrField b(a);
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// Make sure to not ignore cases when the operator definition calls
+// a copy assignment operator of another class.
+class AssignOperator {
+public:
+ AssignOperator &operator=(const AssignOperator &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ a.operator=(object.a);
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+ WeakPtrField a;
+};
+
+class NotSelfCheck {
+public:
+ NotSelfCheck &operator=(const NotSelfCheck &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ if (&object == this->doSomething()) {
+ // ...
+ }
+ return *this;
+ }
+
+ void *doSomething() {
+ return p;
+ }
+
+private:
+ int *p;
+};
+
+template <class T>
+class TemplatePtrField {
+public:
+ TemplatePtrField<T> &operator=(const TemplatePtrField<T> &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ T *p;
+};
+
+template <class T>
+class TemplateCArrayField {
+public:
+ TemplateCArrayField<T> &operator=(const TemplateCArrayField<T> &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ // ...
+ return *this;
+ }
+
+private:
+ T p[256];
+};
+
+// Other template class's constructor is called inside a declaration.
+template <class T>
+class WrongTemplateCopyAndMove {
+public:
+ WrongTemplateCopyAndMove<T> &operator=(const WrongTemplateCopyAndMove<T> &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:32: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ TemplatePtrField<T> temp;
+ TemplatePtrField<T> temp2(temp);
+ return *this;
+ }
+
+private:
+ T *p;
+};
+
+///////////////////////////////////////////////////////////////////
+/// Test cases correctly ignored by the check.
+
+// Self-assignment is checked using the equality operator.
+class SelfCheck1 {
+public:
+ SelfCheck1 &operator=(const SelfCheck1 &object) {
+ if (this == &object)
+ return *this;
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+class SelfCheck2 {
+public:
+ SelfCheck2 &operator=(const SelfCheck2 &object) {
+ if (&object == this)
+ return *this;
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// Self-assignment is checked using the inequality operator.
+class SelfCheck3 {
+public:
+ SelfCheck3 &operator=(const SelfCheck3 &object) {
+ if (this != &object) {
+ // ...
+ }
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+class SelfCheck4 {
+public:
+ SelfCheck4 &operator=(const SelfCheck4 &object) {
+ if (&object != this) {
+ // ...
+ }
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+template <class T>
+class TemplateSelfCheck {
+public:
+ TemplateSelfCheck<T> &operator=(const TemplateSelfCheck<T> &object) {
+ if (&object != this) {
+ // ...
+ }
+ return *this;
+ }
+
+private:
+ T *p;
+};
+
+// There is no warning if the copy assignment operator gets the object by value.
+class PassedByValue {
+public:
+ PassedByValue &operator=(PassedByValue object) {
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// User-defined swap method calling std::swap inside.
+class CopyAndSwap1 {
+public:
+ CopyAndSwap1 &operator=(const CopyAndSwap1 &object) {
+ CopyAndSwap1 temp(object);
+ doSwap(temp);
+ return *this;
+ }
+
+private:
+ int *p;
+
+ void doSwap(CopyAndSwap1 &object) {
+ using std::swap;
+ swap(p, object.p);
+ }
+};
+
+// User-defined swap method used with passed-by-value parameter.
+class CopyAndSwap2 {
+public:
+ CopyAndSwap2 &operator=(CopyAndSwap2 object) {
+ doSwap(object);
+ return *this;
+ }
+
+private:
+ int *p;
+
+ void doSwap(CopyAndSwap2 &object) {
+ using std::swap;
+ swap(p, object.p);
+ }
+};
+
+// Copy-and-swap method is used but without creating a separate method for it.
+class CopyAndSwap3 {
+public:
+ CopyAndSwap3 &operator=(const CopyAndSwap3 &object) {
+ CopyAndSwap3 temp(object);
+ std::swap(p, temp.p);
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+template <class T>
+class TemplateCopyAndSwap {
+public:
+ TemplateCopyAndSwap<T> &operator=(const TemplateCopyAndSwap<T> &object) {
+ TemplateCopyAndSwap<T> temp(object);
+ std::swap(p, temp.p);
+ return *this;
+ }
+
+private:
+ T *p;
+};
+
+// Move semantics is used on a temporary copy of the object.
+class CopyAndMove1 {
+public:
+ CopyAndMove1 &operator=(const CopyAndMove1 &object) {
+ CopyAndMove1 temp(object);
+ *this = std::move(temp);
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// There is no local variable for the temporary copy.
+class CopyAndMove2 {
+public:
+ CopyAndMove2 &operator=(const CopyAndMove2 &object) {
+ *this = std::move(CopyAndMove2(object));
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+template <class T>
+class TemplateCopyAndMove {
+public:
+ TemplateCopyAndMove<T> &operator=(const TemplateCopyAndMove<T> &object) {
+ TemplateCopyAndMove<T> temp(object);
+ *this = std::move(temp);
+ return *this;
+ }
+
+private:
+ T *p;
+};
+
+// There is no local variable for the temporary copy.
+template <class T>
+class TemplateCopyAndMove2 {
+public:
+ TemplateCopyAndMove2<T> &operator=(const TemplateCopyAndMove2<T> &object) {
+ *this = std::move(TemplateCopyAndMove2<T>(object));
+ return *this;
+ }
+
+private:
+ T *p;
+};
+
+// We should not catch move assignment operators.
+class MoveAssignOperator {
+public:
+ MoveAssignOperator &operator=(MoveAssignOperator &&object) {
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// We ignore copy assignment operators without user-defined implementation.
+class DefaultOperator {
+public:
+ DefaultOperator &operator=(const DefaultOperator &object) = default;
+
+private:
+ int *p;
+};
+
+class DeletedOperator {
+public:
+ DeletedOperator &operator=(const DefaultOperator &object) = delete;
+
+private:
+ int *p;
+};
+
+class ImplicitOperator {
+private:
+ int *p;
+};
+
+// Check ignores those classes which has no any pointer or array field.
+class TrivialFields {
+public:
+ TrivialFields &operator=(const TrivialFields &object) {
+ // ...
+ return *this;
+ }
+
+private:
+ int m;
+ float f;
+ double d;
+ bool b;
+};
+
+// There is no warning when the class calls another assignment operator on 'this'
+// inside the copy assignment operator's definition.
+class AssignIsForwarded {
+public:
+ AssignIsForwarded &operator=(const AssignIsForwarded &object) {
+ operator=(object.p);
+ return *this;
+ }
+
+ AssignIsForwarded &operator=(int *pp) {
+ if (p != pp) {
+ delete p;
+ p = new int(*pp);
+ }
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// Assertion is a valid way to say that self-assignment is not expected to happen.
+class AssertGuard {
+public:
+ AssertGuard &operator=(const AssertGuard &object) {
+ assert(this != &object);
+ // ...
+ return *this;
+ }
+
+private:
+ int *p;
+};
+
+// Make sure we don't catch this operator=() as a copy assignment operator.
+// Note that RHS has swapped template arguments.
+template <typename Ty, typename Uy>
+class NotACopyAssignmentOperator {
+ Ty *Ptr1;
+ Uy *Ptr2;
+
+public:
+ NotACopyAssignmentOperator& operator=(const NotACopyAssignmentOperator<Uy, Ty> &RHS) {
+ Ptr1 = RHS.getUy();
+ Ptr2 = RHS.getTy();
+ return *this;
+ }
+
+ Ty *getTy() const { return Ptr1; }
+ Uy *getUy() const { return Ptr2; }
+};
+
+///////////////////////////////////////////////////////////////////
+/// Test cases which should be caught by the check.
+
+// TODO: handle custom pointers.
+template <class T>
+class custom_ptr {
+};
+
+class CustomPtrField {
+public:
+ CustomPtrField &operator=(const CustomPtrField &object) {
+ // ...
+ return *this;
+ }
+
+private:
+ custom_ptr<int> p;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+/// False positives: These are self-assignment safe, but they don't use any of the three patterns.
+
+class ArrayCopy {
+public:
+ ArrayCopy &operator=(const ArrayCopy &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ for (int i = 0; i < 256; i++)
+ array[i] = object.array[i];
+ return *this;
+ }
+
+private:
+ int array[256];
+};
+
+class GetterSetter {
+public:
+ GetterSetter &operator=(const GetterSetter &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ setValue(object.getValue());
+ return *this;
+ }
+
+ int *getValue() const { return value; }
+
+ void setValue(int *newPtr) {
+ int *pTmp(newPtr ? new int(*newPtr) : nullptr);
+ std::swap(value, pTmp);
+ delete pTmp;
+ }
+
+private:
+ int *value;
+};
+
+class CustomSelfCheck {
+public:
+ CustomSelfCheck &operator=(const CustomSelfCheck &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment]
+ if (index != object.index) {
+ // ...
+ }
+ return *this;
+ }
+
+private:
+ int *value;
+ int index;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-raii.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-raii.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-raii.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-raii.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,68 @@
+// RUN: %check_clang_tidy %s bugprone-unused-raii %t
+
+struct Foo {
+ Foo();
+ Foo(int);
+ Foo(int, int);
+ ~Foo();
+};
+
+struct Bar {
+ Bar();
+};
+
+struct FooBar {
+ FooBar();
+ Foo f;
+};
+
+template <typename T>
+void qux() {
+ T(42);
+}
+
+template <typename T>
+struct TFoo {
+ TFoo(T);
+ ~TFoo();
+};
+
+Foo f();
+
+struct Ctor {
+ Ctor(int);
+ Ctor() {
+ Ctor(0); // TODO: warn here.
+ }
+};
+
+void test() {
+ Foo(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name(42);
+ Foo(23, 42);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name(23, 42);
+ Foo();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name;
+ TFoo<int>(23);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: TFoo<int> give_me_a_name(23);
+
+ FooBar();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: FooBar give_me_a_name;
+
+ Bar();
+ f();
+ qux<Foo>();
+
+#define M Foo();
+ M
+
+ {
+ Foo();
+ }
+ Foo();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value-custom.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value-custom.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value-custom.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value-custom.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,108 @@
+// RUN: %check_clang_tidy %s bugprone-unused-return-value %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: bugprone-unused-return-value.CheckedFunctions, \
+// RUN: value: "::fun;::ns::Outer::Inner::memFun;::ns::Type::staticFun;::ns::ClassTemplate::memFun;::ns::ClassTemplate::staticFun"}]}' \
+// RUN: --
+
+namespace std {
+
+template <typename T>
+T *launder(T *);
+
+} // namespace std
+
+namespace ns {
+
+struct Outer {
+ struct Inner {
+ bool memFun();
+ };
+};
+
+using AliasName = Outer;
+
+struct Derived : public Outer::Inner {};
+
+struct Retval {
+ int *P;
+ Retval() { P = new int; }
+ ~Retval() { delete P; }
+};
+
+struct Type {
+ Retval memFun();
+ static Retval staticFun();
+};
+
+template <typename T>
+struct ClassTemplate {
+ Retval memFun();
+ static Retval staticFun();
+};
+
+} // namespace ns
+
+int fun();
+void fun(int);
+
+void warning() {
+ fun();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value returned by this function should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast the expression to void to silence this warning
+
+ (fun());
+ // CHECK-NOTES: [[@LINE-1]]:4: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:4: note: cast {{.*}} this warning
+
+ ns::Outer::Inner ObjA1;
+ ObjA1.memFun();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ ns::AliasName::Inner ObjA2;
+ ObjA2.memFun();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ ns::Derived ObjA3;
+ ObjA3.memFun();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ ns::Type::staticFun();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ ns::ClassTemplate<int> ObjA4;
+ ObjA4.memFun();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ ns::ClassTemplate<int>::staticFun();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+}
+
+void noWarning() {
+ auto R1 = fun();
+
+ ns::Outer::Inner ObjB1;
+ auto R2 = ObjB1.memFun();
+
+ auto R3 = ns::Type::staticFun();
+
+ ns::ClassTemplate<int> ObjB2;
+ auto R4 = ObjB2.memFun();
+
+ auto R5 = ns::ClassTemplate<int>::staticFun();
+
+ // test calling a void overload of a checked function
+ fun(5);
+
+ // test discarding return value of functions that are not configured to be checked
+ int I = 1;
+ std::launder(&I);
+
+ ns::Type ObjB3;
+ ObjB3.memFun();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-unused-return-value.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,238 @@
+// RUN: %check_clang_tidy %s bugprone-unused-return-value %t -- -- -fexceptions
+
+namespace std {
+
+struct future {};
+
+enum class launch {
+ async,
+ deferred
+};
+
+template <typename Function, typename... Args>
+future async(Function &&, Args &&...);
+
+template <typename Function, typename... Args>
+future async(launch, Function &&, Args &&...);
+
+template <typename ForwardIt, typename T>
+ForwardIt remove(ForwardIt, ForwardIt, const T &);
+
+template <typename ForwardIt, typename UnaryPredicate>
+ForwardIt remove_if(ForwardIt, ForwardIt, UnaryPredicate);
+
+template <typename ForwardIt>
+ForwardIt unique(ForwardIt, ForwardIt);
+
+template <typename T>
+struct default_delete;
+
+template <typename T, typename Deleter = std::default_delete<T>>
+struct unique_ptr {
+ T *release() noexcept;
+};
+
+template <typename T>
+struct char_traits;
+
+template <typename T>
+struct allocator;
+
+template <typename CharT,
+ typename Traits = char_traits<CharT>,
+ typename Allocator = allocator<CharT>>
+struct basic_string {
+ bool empty() const;
+};
+
+typedef basic_string<char> string;
+
+template <typename T, typename Allocator = std::allocator<T>>
+struct vector {
+ bool empty() const noexcept;
+};
+
+// the check should be able to match std lib calls even if the functions are
+// declared inside inline namespaces
+inline namespace v1 {
+
+template <typename T>
+T *launder(T *);
+
+} // namespace v1
+} // namespace std
+
+struct Foo {
+ void f();
+};
+
+int increment(int i) {
+ return i + 1;
+}
+
+void useFuture(const std::future &fut);
+
+void warning() {
+ std::async(increment, 42);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value returned by this function should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast the expression to void to silence this warning
+
+ std::async(std::launch::async, increment, 42);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ Foo F;
+ std::launder(&F);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ std::remove_if(nullptr, nullptr, nullptr);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ std::unique(nullptr, nullptr);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ std::unique_ptr<Foo> UPtr;
+ UPtr.release();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ std::string Str;
+ Str.empty();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ std::vector<Foo> Vec;
+ Vec.empty();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:3: note: cast {{.*}} this warning
+
+ // test discarding return values inside different kinds of statements
+
+ auto Lambda = [] { std::remove(nullptr, nullptr, 1); };
+ // CHECK-NOTES: [[@LINE-1]]:22: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:22: note: cast {{.*}} this warning
+
+ if (true)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+ else if (true)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+ else
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+
+ while (true)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+
+ do
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+ while (true);
+
+ for (;;)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+
+ for (std::remove(nullptr, nullptr, 1);;)
+ // CHECK-NOTES: [[@LINE-1]]:8: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:8: note: cast {{.*}} this warning
+ ;
+
+ for (;; std::remove(nullptr, nullptr, 1))
+ // CHECK-NOTES: [[@LINE-1]]:11: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:11: note: cast {{.*}} this warning
+ ;
+
+ for (auto C : "foo")
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+
+ switch (1) {
+ case 1:
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+ break;
+ default:
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+ break;
+ }
+
+ try {
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+ } catch (...) {
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: the value {{.*}} should be used
+ // CHECK-NOTES: [[@LINE-2]]:5: note: cast {{.*}} this warning
+ }
+}
+
+void noWarning() {
+ auto AsyncRetval1 = std::async(increment, 42);
+ auto AsyncRetval2 = std::async(std::launch::async, increment, 42);
+
+ Foo FNoWarning;
+ auto LaunderRetval = std::launder(&FNoWarning);
+
+ auto RemoveRetval = std::remove(nullptr, nullptr, 1);
+
+ auto RemoveIfRetval = std::remove_if(nullptr, nullptr, nullptr);
+
+ auto UniqueRetval = std::unique(nullptr, nullptr);
+
+ std::unique_ptr<Foo> UPtrNoWarning;
+ auto ReleaseRetval = UPtrNoWarning.release();
+
+ std::string StrNoWarning;
+ auto StrEmptyRetval = StrNoWarning.empty();
+
+ std::vector<Foo> VecNoWarning;
+ auto VecEmptyRetval = VecNoWarning.empty();
+
+ // test using the return value in different kinds of expressions
+ useFuture(std::async(increment, 42));
+ std::launder(&FNoWarning)->f();
+ delete std::launder(&FNoWarning);
+
+ if (std::launder(&FNoWarning))
+ ;
+ for (; std::launder(&FNoWarning);)
+ ;
+ while (std::launder(&FNoWarning))
+ ;
+ do
+ ;
+ while (std::launder(&FNoWarning));
+ switch (std::unique(1, 1))
+ ;
+
+ // cast to void should allow ignoring the return value
+ (void)std::async(increment, 42);
+
+ // test discarding return value of functions that are not configured to be checked
+ increment(1);
+
+ // test that the check is disabled inside GNU statement expressions
+ ({ std::async(increment, 42); });
+ auto StmtExprRetval = ({ std::async(increment, 42); });
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-use-after-move.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-use-after-move.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-use-after-move.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-use-after-move.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,1273 @@
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 -fno-delayed-template-parsing
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template <typename T>
+struct unique_ptr {
+ unique_ptr();
+ T *get() const;
+ explicit operator bool() const;
+ void reset(T *ptr);
+ T &operator*() const;
+ T *operator->() const;
+ T& operator[](size_t i) const;
+};
+
+template <typename T>
+struct shared_ptr {
+ shared_ptr();
+ T *get() const;
+ explicit operator bool() const;
+ void reset(T *ptr);
+ T &operator*() const;
+ T *operator->() const;
+};
+
+template <typename T>
+struct weak_ptr {
+ weak_ptr();
+ bool expired() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+ template <typename T> \
+ struct name { \
+ name(); \
+ void clear(); \
+ bool empty(); \
+ }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+ template <typename T> \
+ struct name { \
+ name(); \
+ void clear(); \
+ bool empty(); \
+ void assign(size_t, const T &); \
+ }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string<char> string;
+
+template <typename>
+struct remove_reference;
+
+template <typename _Tp>
+struct remove_reference {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+struct remove_reference<_Tp &> {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+struct remove_reference<_Tp &&> {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+ return static_cast<typename remove_reference<_Tp>::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+ A();
+ A(const A &);
+ A(A &&);
+
+ A &operator=(const A &);
+ A &operator=(A &&);
+
+ void foo() const;
+ int getInt() const;
+
+ operator bool() const;
+
+ int i;
+};
+
+template <class T>
+class AnnotatedContainer {
+public:
+ AnnotatedContainer();
+
+ void foo() const;
+ [[clang::reinitializes]] void clear();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// General tests.
+
+// Simple case.
+void simple() {
+ A a;
+ a.foo();
+ A other_a = std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+ A a;
+ a.foo();
+ A other_a = std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:15: note: move occurred here
+ a.foo();
+}
+
+void moveAfterMove() {
+ // Move-after-move also counts as a use.
+ {
+ A a;
+ std::move(a);
+ std::move(a);
+ // CHECK-NOTES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // This is also true if the move itself turns into the use on the second loop
+ // iteration.
+ {
+ A a;
+ for (int i = 0; i < 10; ++i) {
+ std::move(a);
+ // CHECK-NOTES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:7: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:17: note: the use happens in a later loop
+ }
+ }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+ std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void standardSmartPtr() {
+ // std::unique_ptr<>, std::shared_ptr<> and std::weak_ptr<> are guaranteed to
+ // be null after a std::move. So the check only flags accesses that would
+ // dereference the pointer.
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr.get();
+ static_cast<bool>(ptr);
+ *ptr;
+ // CHECK-NOTES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+ // CHECK-NOTES: [[@LINE-5]]:5: note: move occurred here
+ }
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr->foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr[0];
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ std::shared_ptr<A> ptr;
+ std::move(ptr);
+ ptr.get();
+ static_cast<bool>(ptr);
+ *ptr;
+ // CHECK-NOTES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+ // CHECK-NOTES: [[@LINE-5]]:5: note: move occurred here
+ }
+ {
+ std::shared_ptr<A> ptr;
+ std::move(ptr);
+ ptr->foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ // std::weak_ptr<> cannot be dereferenced directly, so we only check that
+ // member functions may be called on it after a move.
+ std::weak_ptr<A> ptr;
+ std::move(ptr);
+ ptr.expired();
+ }
+ // Make sure we recognize std::unique_ptr<> or std::shared_ptr<> if they're
+ // wrapped in a typedef.
+ {
+ typedef std::unique_ptr<A> PtrToA;
+ PtrToA ptr;
+ std::move(ptr);
+ ptr.get();
+ }
+ {
+ typedef std::shared_ptr<A> PtrToA;
+ PtrToA ptr;
+ std::move(ptr);
+ ptr.get();
+ }
+ // And we don't get confused if the template argument is a little more
+ // involved.
+ {
+ struct B {
+ typedef A AnotherNameForA;
+ };
+ std::unique_ptr<B::AnotherNameForA> ptr;
+ std::move(ptr);
+ ptr.get();
+ }
+ // Make sure we treat references to smart pointers correctly.
+ {
+ std::unique_ptr<A> ptr;
+ std::unique_ptr<A>& ref_to_ptr = ptr;
+ std::move(ref_to_ptr);
+ ref_to_ptr.get();
+ }
+ {
+ std::unique_ptr<A> ptr;
+ std::unique_ptr<A>&& rvalue_ref_to_ptr = std::move(ptr);
+ std::move(rvalue_ref_to_ptr);
+ rvalue_ref_to_ptr.get();
+ }
+ // We don't give any special treatment to types that are called "unique_ptr"
+ // or "shared_ptr" but are not in the "::std" namespace.
+ {
+ struct unique_ptr {
+ void get();
+ } ptr;
+ std::move(ptr);
+ ptr.get();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+}
+
+// The check also works in member functions.
+class Container {
+ void useAfterMoveInMemberFunction() {
+ A a;
+ std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+};
+
+// We see the std::move() if it's inside a declaration.
+void moveInDeclaration() {
+ A a;
+ A another_a(std::move(a));
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+}
+
+// We see the std::move if it's inside an initializer list. Initializer lists
+// are a special case because they cause ASTContext::getParents() to return
+// multiple parents for certain nodes in their subtree. This is because
+// RecursiveASTVisitor visits both the syntactic and semantic forms of
+// InitListExpr, and the parent-child relationships are different between the
+// two forms.
+void moveInInitList() {
+ struct S {
+ A a;
+ };
+ A a;
+ S s{std::move(a)};
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
+}
+
+void lambdas() {
+ // Use-after-moves inside a lambda should be detected.
+ {
+ A a;
+ auto lambda = [a] {
+ std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
+ };
+ }
+ // This is just as true if the variable was declared inside the lambda.
+ {
+ auto lambda = [] {
+ A a;
+ std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:7: note: move occurred here
+ };
+ }
+ // But don't warn if the move happened inside the lambda but the use happened
+ // outside -- because
+ // - the 'a' inside the lambda is a copy, and
+ // - we don't know when the lambda will get called anyway
+ {
+ A a;
+ auto lambda = [a] {
+ std::move(a);
+ };
+ a.foo();
+ }
+ // Warn if the use consists of a capture that happens after a move.
+ {
+ A a;
+ std::move(a);
+ auto lambda = [a]() { a.foo(); };
+ // CHECK-NOTES: [[@LINE-1]]:20: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // ...even if the capture was implicit.
+ {
+ A a;
+ std::move(a);
+ auto lambda = [=]() { a.foo(); };
+ // CHECK-NOTES: [[@LINE-1]]:20: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // Same tests but for capture by reference.
+ {
+ A a;
+ std::move(a);
+ auto lambda = [&a]() { a.foo(); };
+ // CHECK-NOTES: [[@LINE-1]]:21: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ A a;
+ std::move(a);
+ auto lambda = [&]() { a.foo(); };
+ // CHECK-NOTES: [[@LINE-1]]:20: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // But don't warn if the move happened after the capture.
+ {
+ A a;
+ auto lambda = [a]() { a.foo(); };
+ std::move(a);
+ }
+ // ...and again, same thing with an implicit move.
+ {
+ A a;
+ auto lambda = [=]() { a.foo(); };
+ std::move(a);
+ }
+ // Same tests but for capture by reference.
+ {
+ A a;
+ auto lambda = [&a]() { a.foo(); };
+ std::move(a);
+ }
+ {
+ A a;
+ auto lambda = [&]() { a.foo(); };
+ std::move(a);
+ }
+}
+
+// Use-after-moves are detected in uninstantiated templates if the moved type
+// is not a dependent type.
+template <class T>
+void movedTypeIsNotDependentType() {
+ T t;
+ A a;
+ std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
+}
+
+// And if the moved type is a dependent type, the use-after-move is detected if
+// the template is instantiated.
+template <class T>
+void movedTypeIsDependentType() {
+ T t;
+ std::move(t);
+ t.foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 't' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
+}
+template void movedTypeIsDependentType<A>();
+
+// We handle the case correctly where the move consists of an implicit call
+// to a conversion operator.
+void implicitConversionOperator() {
+ struct Convertible {
+ operator A() && { return A(); }
+ };
+ void takeA(A a);
+
+ Convertible convertible;
+ takeA(std::move(convertible));
+ convertible;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: 'convertible' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:9: note: move occurred here
+}
+
+// Using decltype on an expression is not a use.
+void decltypeIsNotUse() {
+ A a;
+ std::move(a);
+ decltype(a) other_a;
+}
+
+// Ignore moves or uses that occur as part of template arguments.
+template <int>
+class ClassTemplate {
+public:
+ void foo(A a);
+};
+template <int>
+void functionTemplate(A a);
+void templateArgIsNotUse() {
+ {
+ // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
+ // Google Test.
+ A a;
+ ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a));
+ }
+ {
+ A a;
+ functionTemplate<sizeof(A(std::move(a)))>(std::move(a));
+ }
+}
+
+// Ignore moves of global variables.
+A global_a;
+void ignoreGlobalVariables() {
+ std::move(global_a);
+ global_a.foo();
+}
+
+// Ignore moves of member variables.
+class IgnoreMemberVariables {
+ A a;
+ static A static_a;
+
+ void f() {
+ std::move(a);
+ a.foo();
+
+ std::move(static_a);
+ static_a.foo();
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests involving control flow.
+
+void useAndMoveInLoop() {
+ // Warn about use-after-moves if they happen in a later loop iteration than
+ // the std::move().
+ {
+ A a;
+ for (int i = 0; i < 10; ++i) {
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE+2]]:7: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:7: note: the use happens in a later loop
+ std::move(a);
+ }
+ }
+ // However, this case shouldn't be flagged -- the scope of the declaration of
+ // 'a' is important.
+ {
+ for (int i = 0; i < 10; ++i) {
+ A a;
+ a.foo();
+ std::move(a);
+ }
+ }
+ // Same as above, except that we have an unrelated variable being declared in
+ // the same declaration as 'a'. This case is interesting because it tests that
+ // the synthetic DeclStmts generated by the CFG are sequenced correctly
+ // relative to the other statements.
+ {
+ for (int i = 0; i < 10; ++i) {
+ A a, other;
+ a.foo();
+ std::move(a);
+ }
+ }
+ // Don't warn if we return after the move.
+ {
+ A a;
+ for (int i = 0; i < 10; ++i) {
+ a.foo();
+ if (a.getInt() > 0) {
+ std::move(a);
+ return;
+ }
+ }
+ }
+}
+
+void differentBranches(int i) {
+ // Don't warn if the use is in a different branch from the move.
+ {
+ A a;
+ if (i > 0) {
+ std::move(a);
+ } else {
+ a.foo();
+ }
+ }
+ // Same thing, but with a ternary operator.
+ {
+ A a;
+ i > 0 ? (void)std::move(a) : a.foo();
+ }
+ // A variation on the theme above.
+ {
+ A a;
+ a.getInt() > 0 ? a.getInt() : A(std::move(a)).getInt();
+ }
+ // Same thing, but with a switch statement.
+ {
+ A a;
+ switch (i) {
+ case 1:
+ std::move(a);
+ break;
+ case 2:
+ a.foo();
+ break;
+ }
+ }
+ // However, if there's a fallthrough, we do warn.
+ {
+ A a;
+ switch (i) {
+ case 1:
+ std::move(a);
+ case 2:
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-4]]:7: note: move occurred here
+ break;
+ }
+ }
+}
+
+// False positive: A use-after-move is flagged even though the "if (b)" and
+// "if (!b)" are mutually exclusive.
+void mutuallyExclusiveBranchesFalsePositive(bool b) {
+ A a;
+ if (b) {
+ std::move(a);
+ }
+ if (!b) {
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-5]]:5: note: move occurred here
+ }
+}
+
+// Destructors marked [[noreturn]] are handled correctly in the control flow
+// analysis. (These are used in some styles of assertion macros.)
+class FailureLogger {
+public:
+ FailureLogger();
+ [[noreturn]] ~FailureLogger();
+ void log(const char *);
+};
+#define ASSERT(x) \
+ while (x) \
+ FailureLogger().log(#x)
+bool operationOnA(A);
+void noreturnDestructor() {
+ A a;
+ // The while loop in the ASSERT() would ordinarily have the potential to cause
+ // a use-after-move because the second iteration of the loop would be using a
+ // variable that had been moved from in the first iteration. Check that the
+ // CFG knows that the second iteration of the loop is never reached because
+ // the FailureLogger destructor is marked [[noreturn]].
+ ASSERT(operationOnA(std::move(a)));
+}
+#undef ASSERT
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests for reinitializations
+
+template <class T>
+void swap(T &a, T &b) {
+ T tmp = std::move(a);
+ a = std::move(b);
+ b = std::move(tmp);
+}
+void assignments(int i) {
+ // Don't report a use-after-move if the variable was assigned to in the
+ // meantime.
+ {
+ A a;
+ std::move(a);
+ a = A();
+ a.foo();
+ }
+ // The assignment should also be recognized if move, assignment and use don't
+ // all happen in the same block (but the assignment is still guaranteed to
+ // prevent a use-after-move).
+ {
+ A a;
+ if (i == 1) {
+ std::move(a);
+ a = A();
+ }
+ if (i == 2) {
+ a.foo();
+ }
+ }
+ {
+ A a;
+ if (i == 1) {
+ std::move(a);
+ }
+ if (i == 2) {
+ a = A();
+ a.foo();
+ }
+ }
+ // The built-in assignment operator should also be recognized as a
+ // reinitialization. (std::move() may be called on built-in types in template
+ // code.)
+ {
+ int a1 = 1, a2 = 2;
+ swap(a1, a2);
+ }
+ // A std::move() after the assignment makes the variable invalid again.
+ {
+ A a;
+ std::move(a);
+ a = A();
+ std::move(a);
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // Report a use-after-move if we can't be sure that the variable was assigned
+ // to.
+ {
+ A a;
+ std::move(a);
+ if (i < 10) {
+ a = A();
+ }
+ if (i > 5) {
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-7]]:5: note: move occurred here
+ }
+ }
+}
+
+// Passing the object to a function through a non-const pointer or reference
+// counts as a re-initialization.
+void passByNonConstPointer(A *);
+void passByNonConstReference(A &);
+void passByNonConstPointerIsReinit() {
+ {
+ A a;
+ std::move(a);
+ passByNonConstPointer(&a);
+ a.foo();
+ }
+ {
+ A a;
+ std::move(a);
+ passByNonConstReference(a);
+ a.foo();
+ }
+}
+
+// Passing the object through a const pointer or reference counts as a use --
+// since the called function cannot reinitialize the object.
+void passByConstPointer(const A *);
+void passByConstReference(const A &);
+void passByConstPointerIsUse() {
+ {
+ // Declaring 'a' as const so that no ImplicitCastExpr is inserted into the
+ // AST -- we wouldn't want the check to rely solely on that to detect a
+ // const pointer argument.
+ const A a;
+ std::move(a);
+ passByConstPointer(&a);
+ // CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ const A a;
+ std::move(a);
+ passByConstReference(a);
+ // CHECK-NOTES: [[@LINE-1]]:24: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:3: note: move occurred here
+}
+
+// Clearing a standard container using clear() is treated as a
+// re-initialization.
+void standardContainerClearIsReinit() {
+ {
+ std::string container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::vector<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+
+ auto container2 = container;
+ std::move(container2);
+ container2.clear();
+ container2.empty();
+ }
+ {
+ std::deque<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::forward_list<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::list<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::set<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::map<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::multiset<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::multimap<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_set<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_map<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_multiset<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_multimap<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ // This should also work for typedefs of standard containers.
+ {
+ typedef std::vector<int> IntVector;
+ IntVector container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ // But it shouldn't work for non-standard containers.
+ {
+ // This might be called "vector", but it's not in namespace "std".
+ struct vector {
+ void clear() {}
+ } container;
+ std::move(container);
+ container.clear();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container' used after it was
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // An intervening clear() on a different container does not reinitialize.
+ {
+ std::vector<int> container1, container2;
+ std::move(container1);
+ container2.clear();
+ container1.empty();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container1' used after it was
+ // CHECK-NOTES: [[@LINE-4]]:5: note: move occurred here
+ }
+}
+
+// Clearing a standard container using assign() is treated as a
+// re-initialization.
+void standardContainerAssignIsReinit() {
+ {
+ std::string container;
+ std::move(container);
+ container.assign(0, ' ');
+ container.empty();
+ }
+ {
+ std::vector<int> container;
+ std::move(container);
+ container.assign(0, 0);
+ container.empty();
+ }
+ {
+ std::deque<int> container;
+ std::move(container);
+ container.assign(0, 0);
+ container.empty();
+ }
+ {
+ std::forward_list<int> container;
+ std::move(container);
+ container.assign(0, 0);
+ container.empty();
+ }
+ {
+ std::list<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ // But it doesn't work for non-standard containers.
+ {
+ // This might be called "vector", but it's not in namespace "std".
+ struct vector {
+ void assign(std::size_t, int) {}
+ } container;
+ std::move(container);
+ container.assign(0, 0);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container' used after it was
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // An intervening assign() on a different container does not reinitialize.
+ {
+ std::vector<int> container1, container2;
+ std::move(container1);
+ container2.assign(0, 0);
+ container1.empty();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'container1' used after it was
+ // CHECK-NOTES: [[@LINE-4]]:5: note: move occurred here
+ }
+}
+
+// Resetting the standard smart pointer types using reset() is treated as a
+// re-initialization. (We don't test std::weak_ptr<> because it can't be
+// dereferenced directly.)
+void standardSmartPointerResetIsReinit() {
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr.reset(new A);
+ *ptr;
+ }
+ {
+ std::shared_ptr<A> ptr;
+ std::move(ptr);
+ ptr.reset(new A);
+ *ptr;
+ }
+}
+
+void reinitAnnotation() {
+ {
+ AnnotatedContainer<int> obj;
+ std::move(obj);
+ obj.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'obj' used after it was
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ AnnotatedContainer<int> obj;
+ std::move(obj);
+ obj.clear();
+ obj.foo();
+ }
+ {
+ // Calling clear() on a different object to the one that was moved is not
+ // considered a reinitialization.
+ AnnotatedContainer<int> obj1, obj2;
+ std::move(obj1);
+ obj2.clear();
+ obj1.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+ // CHECK-NOTES: [[@LINE-4]]:5: note: move occurred here
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests related to order of evaluation within expressions
+
+// Relative sequencing of move and use.
+void passByRvalueReference(int i, A &&a);
+void passByValue(int i, A a);
+void passByValue(A a, int i);
+A g(A, A &&);
+int intFromA(A &&);
+int intFromInt(int);
+void sequencingOfMoveAndUse() {
+ // This case is fine because the move only happens inside
+ // passByRvalueReference(). At this point, a.getInt() is guaranteed to have
+ // been evaluated.
+ {
+ A a;
+ passByRvalueReference(a.getInt(), std::move(a));
+ }
+ // However, if we pass by value, the move happens when the move constructor is
+ // called to create a temporary, and this happens before the call to
+ // passByValue(). Because the order in which arguments are evaluated isn't
+ // defined, the move may happen before the call to a.getInt().
+ //
+ // Check that we warn about a potential use-after move for both orderings of
+ // a.getInt() and std::move(a), independent of the order in which the
+ // arguments happen to get evaluated by the compiler.
+ {
+ A a;
+ passByValue(a.getInt(), std::move(a));
+ // CHECK-NOTES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:29: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:17: note: the use and move are unsequenced
+ }
+ {
+ A a;
+ passByValue(std::move(a), a.getInt());
+ // CHECK-NOTES: [[@LINE-1]]:31: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:17: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:31: note: the use and move are unsequenced
+ }
+ // An even more convoluted example.
+ {
+ A a;
+ g(g(a, std::move(a)), g(a, std::move(a)));
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:27: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:9: note: the use and move are unsequenced
+ // CHECK-NOTES: [[@LINE-4]]:29: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-5]]:7: note: move occurred here
+ // CHECK-NOTES: [[@LINE-6]]:29: note: the use and move are unsequenced
+ }
+ // This case is fine because the actual move only happens inside the call to
+ // operator=(). a.getInt(), by necessity, is evaluated before that call.
+ {
+ A a;
+ A vec[1];
+ vec[a.getInt()] = std::move(a);
+ }
+ // However, in the following case, the move happens before the assignment, and
+ // so the order of evaluation is not guaranteed.
+ {
+ A a;
+ int v[3];
+ v[a.getInt()] = intFromA(std::move(a));
+ // CHECK-NOTES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:21: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:7: note: the use and move are unsequenced
+ }
+ {
+ A a;
+ int v[3];
+ v[intFromA(std::move(a))] = intFromInt(a.i);
+ // CHECK-NOTES: [[@LINE-1]]:44: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:7: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:44: note: the use and move are unsequenced
+ }
+}
+
+// Relative sequencing of move and reinitialization. If the two are unsequenced,
+// we conservatively assume that the move happens after the reinitialization,
+// i.e. the that object does not get reinitialized after the move.
+A MutateA(A a);
+void passByValue(A a1, A a2);
+void sequencingOfMoveAndReinit() {
+ // Move and reinitialization as function arguments (which are indeterminately
+ // sequenced). Again, check that we warn for both orderings.
+ {
+ A a;
+ passByValue(std::move(a), (a = A()));
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:17: note: move occurred here
+ }
+ {
+ A a;
+ passByValue((a = A()), std::move(a));
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:28: note: move occurred here
+ }
+ // Common usage pattern: Move the object to a function that mutates it in some
+ // way, then reassign the result to the object. This pattern is fine.
+ {
+ A a;
+ a = MutateA(std::move(a));
+ a.foo();
+ }
+}
+
+// Relative sequencing of reinitialization and use. If the two are unsequenced,
+// we conservatively assume that the reinitialization happens after the use,
+// i.e. that the object is not reinitialized at the point in time when it is
+// used.
+void sequencingOfReinitAndUse() {
+ // Reinitialization and use in function arguments. Again, check both possible
+ // orderings.
+ {
+ A a;
+ std::move(a);
+ passByValue(a.getInt(), (a = A()));
+ // CHECK-NOTES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ A a;
+ std::move(a);
+ passByValue((a = A()), a.getInt());
+ // CHECK-NOTES: [[@LINE-1]]:28: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:5: note: move occurred here
+ }
+}
+
+// The comma operator sequences its operands.
+void commaOperatorSequences() {
+ {
+ A a;
+ A(std::move(a))
+ , (a = A());
+ a.foo();
+ }
+ {
+ A a;
+ (a = A()), A(std::move(a));
+ a.foo();
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-3]]:16: note: move occurred here
+ }
+}
+
+// An initializer list sequences its initialization clauses.
+void initializerListSequences() {
+ {
+ struct S1 {
+ int i;
+ A a;
+ };
+ A a;
+ S1 s1{a.getInt(), std::move(a)};
+ }
+ {
+ struct S2 {
+ A a;
+ int i;
+ };
+ A a;
+ S2 s2{std::move(a), a.getInt()};
+ // CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here
+ }
+}
+
+// A declaration statement containing multiple declarations sequences the
+// initializer expressions.
+void declarationSequences() {
+ {
+ A a;
+ A a1 = a, a2 = std::move(a);
+ }
+ {
+ A a;
+ A a1 = std::move(a), a2 = a;
+ // CHECK-NOTES: [[@LINE-1]]:31: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:12: note: move occurred here
+ }
+}
+
+// The logical operators && and || sequence their operands.
+void logicalOperatorsSequence() {
+ {
+ A a;
+ if (a.getInt() > 0 && A(std::move(a)).getInt() > 0) {
+ A().foo();
+ }
+ }
+ // A variation: Negate the result of the && (which pushes the && further down
+ // into the AST).
+ {
+ A a;
+ if (!(a.getInt() > 0 && A(std::move(a)).getInt() > 0)) {
+ A().foo();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).getInt() > 0 && a.getInt() > 0) {
+ // CHECK-NOTES: [[@LINE-1]]:41: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:9: note: move occurred here
+ A().foo();
+ }
+ }
+ {
+ A a;
+ if (a.getInt() > 0 || A(std::move(a)).getInt() > 0) {
+ A().foo();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).getInt() > 0 || a.getInt() > 0) {
+ // CHECK-NOTES: [[@LINE-1]]:41: warning: 'a' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:9: note: move occurred here
+ A().foo();
+ }
+ }
+}
+
+// A range-based for sequences the loop variable declaration before the body.
+void forRangeSequences() {
+ A v[2] = {A(), A()};
+ for (A &a : v) {
+ std::move(a);
+ }
+}
+
+// If a variable is declared in an if, while or switch statement, the init
+// statement (for if and switch) is sequenced before the variable declaration,
+// which in turn is sequenced before the evaluation of the condition. We place
+// all tests inside a for loop to ensure that the checker understands the
+// sequencing. If it didn't, then the loop would trigger the "moved twice"
+// logic.
+void ifWhileAndSwitchSequenceInitDeclAndCondition() {
+ for (int i = 0; i < 10; ++i) {
+ A a1;
+ if (A a2 = std::move(a1)) {
+ std::move(a2);
+ }
+ }
+ for (int i = 0; i < 10; ++i) {
+ A a1;
+ if (A a2 = std::move(a1); a2) {
+ std::move(a2);
+ }
+ }
+ for (int i = 0; i < 10; ++i) {
+ A a1;
+ if (A a2 = std::move(a1); A a3 = std::move(a2)) {
+ std::move(a3);
+ }
+ }
+ for (int i = 0; i < 10; ++i) {
+ // init followed by condition with move, but without variable declaration.
+ if (A a1; A(std::move(a1)).getInt() > 0) {}
+ }
+ for (int i = 0; i < 10; ++i) {
+ if (A a1; A(std::move(a1)).getInt() > a1.getInt()) {}
+ // CHECK-NOTES: [[@LINE-1]]:43: warning: 'a1' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:15: note: move occurred here
+ // CHECK-NOTES: [[@LINE-3]]:43: note: the use and move are unsequenced
+ }
+ for (int i = 0; i < 10; ++i) {
+ A a1;
+ if (A a2 = std::move(a1); A(a1) > 0) {}
+ // CHECK-NOTES: [[@LINE-1]]:33: warning: 'a1' used after it was moved
+ // CHECK-NOTES: [[@LINE-2]]:16: note: move occurred here
+ }
+ while (A a = A()) {
+ std::move(a);
+ }
+ for (int i = 0; i < 10; ++i) {
+ A a1;
+ switch (A a2 = std::move(a1); a2) {
+ case true:
+ std::move(a2);
+ }
+ }
+ for (int i = 0; i < 10; ++i) {
+ A a1;
+ switch (A a2 = a1; A a3 = std::move(a2)) {
+ case true:
+ std::move(a3);
+ }
+ }
+}
+
+// Some statements in templates (e.g. null, break and continue statements) may
+// be shared between the uninstantiated and instantiated versions of the
+// template and therefore have multiple parents. Make sure the sequencing code
+// handles this correctly.
+template <class> void nullStatementSequencesInTemplate() {
+ int c = 0;
+ (void)c;
+ ;
+ std::move(c);
+}
+template void nullStatementSequencesInTemplate<int>();
+
+namespace PR33020 {
+class D {
+ ~D();
+};
+struct A {
+ D d;
+};
+class B {
+ A a;
+};
+template <typename T>
+class C : T, B {
+ void m_fn1() {
+ int a;
+ std::move(a);
+ C c;
+ }
+};
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-virtual-near-miss.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-virtual-near-miss.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-virtual-near-miss.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/bugprone-virtual-near-miss.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,133 @@
+// RUN: %check_clang_tidy %s bugprone-virtual-near-miss %t
+
+class NoDefinedClass1;
+class NoDefinedClass2;
+
+struct Base {
+ virtual void func();
+ virtual void gunk();
+ virtual ~Base();
+ virtual Base &operator=(const Base &);
+ virtual NoDefinedClass1 *f();
+};
+
+struct Derived : Base {
+ // Should not warn "do you want to override 'gunk'?", because gunk is already
+ // overriden by this class.
+ virtual void funk();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Derived::funk' has a similar name and the same signature as virtual method 'Base::func'; did you mean to override it? [bugprone-virtual-near-miss]
+ // CHECK-FIXES: virtual void func();
+
+ void func2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Derived::func2' has {{.*}} 'Base::func'
+ // CHECK-FIXES: void func();
+
+ void func22(); // Should not warn.
+
+ void gunk(); // Should not warn: gunk is override.
+
+ void fun();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Derived::fun' has {{.*}} 'Base::func'
+ // CHECK-FIXES: void func();
+
+ Derived &operator==(const Base &); // Should not warn: operators are ignored.
+
+ virtual NoDefinedClass2 *f1(); // Should not crash: non-defined class return type is ignored.
+};
+
+template <typename T>
+struct TBase {
+ virtual void tfunc(T t);
+};
+
+template <typename T>
+struct TDerived : TBase<T> {
+ virtual void tfunk(T t);
+ // Should not apply fix for template.
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: method 'TDerived<double>::tfunk' has {{.*}} 'TBase<double>::tfunc'
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: method 'TDerived<int>::tfunk' has {{.*}} 'TBase<int>::tfunc'
+ // CHECK-FIXES: virtual void tfunk(T t);
+};
+
+TDerived<int> T1;
+TDerived<double> T2;
+
+// Should not fix macro definition
+#define MACRO1 void funcM()
+// CHECK-FIXES: #define MACRO1 void funcM()
+#define MACRO2(m) void m()
+// CHECK-FIXES: #define MACRO2(m) void m()
+
+struct DerivedMacro : Base {
+ MACRO1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'DerivedMacro::funcM' has {{.*}} 'Base::func'
+ // CHECK-FIXES: MACRO1;
+
+ MACRO2(func3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'DerivedMacro::func3' has {{.*}} 'Base::func'
+ // CHECK-FIXES: MACRO2(func);
+};
+
+typedef Derived derived_type;
+
+class Father {
+public:
+ Father();
+ virtual void func();
+ virtual Father *create(int i);
+ virtual Base &&generate();
+ virtual Base *canonical(Derived D);
+};
+
+class Mother {
+public:
+ Mother();
+ static void method();
+ virtual int method(int argc, const char **argv);
+ virtual int method(int argc) const;
+ virtual int decay(const char *str);
+};
+
+class Child : private Father, private Mother {
+public:
+ Child();
+
+ virtual void func2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::func2' has {{.*}} 'Father::func'
+ // CHECK-FIXES: virtual void func();
+
+ int methoe(int x, char **strs); // Should not warn: parameter types don't match.
+
+ int methoe(int x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::methoe' has {{.*}} 'Mother::method'
+ // CHECK-FIXES: int method(int x);
+
+ void methof(int x, const char **strs); // Should not warn: return types don't match.
+
+ int methoh(int x, const char **strs);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::methoh' has {{.*}} 'Mother::method'
+ // CHECK-FIXES: int method(int x, const char **strs);
+
+ virtual Child *creat(int i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::creat' has {{.*}} 'Father::create'
+ // CHECK-FIXES: virtual Child *create(int i);
+
+ virtual Derived &&generat();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::generat' has {{.*}} 'Father::generate'
+ // CHECK-FIXES: virtual Derived &&generate();
+
+ int decaz(const char str[]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::decaz' has {{.*}} 'Mother::decay'
+ // CHECK-FIXES: int decay(const char str[]);
+
+ operator bool();
+
+ derived_type *canonica(derived_type D);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::canonica' has {{.*}} 'Father::canonical'
+ // CHECK-FIXES: derived_type *canonical(derived_type D);
+
+private:
+ void funk();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::funk' has {{.*}} 'Father::func'
+ // CHECK-FIXES: void func();
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl21-cpp.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl21-cpp.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl21-cpp.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl21-cpp.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,134 @@
+// RUN: %check_clang_tidy %s cert-dcl21-cpp %t
+
+class A {};
+
+A operator++(A &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a non-constant object instead of a constant object type [cert-dcl21-cpp]
+// CHECK-FIXES: {{^}}const A operator++(A &, int);
+
+A operator--(A &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a no
+// CHECK-FIXES: {{^}}const A operator--(A &, int);
+
+class B {};
+
+B &operator++(B &);
+const B operator++(B &, int);
+
+B &operator--(B &);
+const B operator--(B &, int);
+
+
+class D {
+D &operator++();
+const D operator++(int);
+
+D &operator--();
+const D operator--(int);
+};
+
+class C {
+C operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a no
+// CHECK-FIXES: {{^}}const C operator++(int);
+
+C operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a no
+// CHECK-FIXES: {{^}}const C operator--(int);
+};
+
+class E {};
+
+E &operator++(E &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a reference instead of a constant object type [cert-dcl21-cpp]
+// CHECK-FIXES: {{^}}const E operator++(E &, int);
+
+E &operator--(E &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const E operator--(E &, int);
+
+class G {
+G &operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const G operator++(int);
+
+G &operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const G operator--(int);
+};
+
+class F {};
+
+const F &operator++(F &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const F operator++(F &, int);
+
+const F &operator--(F &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const F operator--(F &, int);
+
+class H {
+const H &operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const H operator++(int);
+
+const H &operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const H operator--(int);
+};
+
+
+#define FROM_MACRO P&
+class P {
+const FROM_MACRO operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const FROM_MACRO operator++(int);
+};
+
+
+template<typename T>
+class Q {
+const Q &operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const Q<T> operator++(int);
+
+const Q &operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const Q<T> operator--(int);
+};
+
+void foobar() {
+ Q<int> a;
+ Q<float> b;
+ (void)a;
+ (void)b;
+}
+
+struct S {};
+typedef S& SRef;
+
+SRef operator++(SRef, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}SRef operator++(SRef, int);
+
+struct T {
+ typedef T& TRef;
+
+ TRef operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}} TRef operator++(int);
+};
+
+struct U {
+ typedef const U& ConstURef;
+
+ ConstURef& operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}} ConstURef& operator++(int);
+};
+
+struct V {
+ V *operator++(int);
+ V *const operator--(int);
+};
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl58-cpp.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl58-cpp.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl58-cpp.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-dcl58-cpp.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s cert-dcl58-cpp %t -- -- -std=c++1z -I %S/Inputs/Headers
+
+#include "system-header-simulation.h"
+
+namespace A {
+ namespace B {
+ int b;
+ }
+}
+
+namespace A {
+ namespace B {
+ int c;
+ }
+}
+
+namespace posix {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'posix' namespace can result in undefined behavior [cert-dcl58-cpp]
+ namespace vmi {
+ }
+}
+
+namespace std {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'std' namespace can
+ int stdInt;
+}
+
+namespace foobar {
+ namespace std {
+ int bar;
+ }
+}
+
+namespace posix::a {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'posix' namespace
+}
+
+enum class MyError {
+ ErrorA,
+ ErrorB
+};
+
+namespace std {
+template <>
+struct is_error_code_enum<MyError> : std::true_type {};
+
+template<>
+void swap<MyError>(MyError &a, MyError &b);
+}
+
+enum class MyError2 {
+ Error2A,
+ Error2B
+};
+
+namespace std {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'std' namespace
+template <>
+struct is_error_code_enum<MyError2> : std::true_type {};
+
+int foobar;
+}
+
+using namespace std;
+
+int x;
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-env33-c.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-env33-c.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-env33-c.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-env33-c.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s cert-env33-c %t
+
+typedef struct FILE {} FILE;
+
+extern int system(const char *);
+extern FILE *popen(const char *, const char *);
+extern FILE *_popen(const char *, const char *);
+
+void f(void) {
+ // It is permissible to check for the presence of a command processor.
+ system(0);
+
+ system("test");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'system' uses a command processor [cert-env33-c]
+
+ popen("test", "test");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'popen' uses a command processor
+ _popen("test", "test");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling '_popen' uses a command processor
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s cert-err34-c %t -- -- -std=c11
+
+typedef __SIZE_TYPE__ size_t;
+typedef signed ptrdiff_t;
+typedef long long intmax_t;
+typedef unsigned long long uintmax_t;
+typedef void * FILE;
+
+extern FILE *stdin;
+
+extern int fscanf(FILE * restrict stream, const char * restrict format, ...);
+extern int scanf(const char * restrict format, ...);
+extern int sscanf(const char * restrict s, const char * restrict format, ...);
+
+extern double atof(const char *nptr);
+extern int atoi(const char *nptr);
+extern long int atol(const char *nptr);
+extern long long int atoll(const char *nptr);
+
+void f1(const char *in) {
+ int i;
+ long long ll;
+ unsigned int ui;
+ unsigned long long ull;
+ intmax_t im;
+ uintmax_t uim;
+ float f;
+ double d;
+ long double ld;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ sscanf(in, "%d", &i);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ fscanf(stdin, "%lld", &ll);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoul' instead [cert-err34-c]
+ sscanf(in, "%u", &ui);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoull' instead [cert-err34-c]
+ fscanf(stdin, "%llu", &ull);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoimax' instead [cert-err34-c]
+ scanf("%jd", &im);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoumax' instead [cert-err34-c]
+ fscanf(stdin, "%ju", &uim);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtof' instead [cert-err34-c]
+ sscanf(in, "%f", &f); // to float
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c]
+ fscanf(stdin, "%lg", &d);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtold' instead [cert-err34-c]
+ sscanf(in, "%Le", &ld);
+
+ // These are conversions with other modifiers
+ short s;
+ char c;
+ size_t st;
+ ptrdiff_t pt;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%hhd", &c);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%hd", &s);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%zu", &st);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%td", &pt);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%o", ui);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%X", ui);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%x", ui);
+}
+
+void f2(const char *in) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: 'atoi' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ int i = atoi(in); // to int
+ // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: 'atol' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ long l = atol(in); // to long
+ // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'atoll' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ long long ll = atoll(in); // to long long
+ // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: 'atof' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c]
+ double d = atof(in); // to double
+}
+
+void f3(void) {
+ int i;
+ unsigned int u;
+ float f;
+ char str[32];
+
+ // Test that we don't report multiple infractions for a single call.
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%d%u%f", &i, &u, &f);
+
+ // Test that we still catch infractions that are not the first specifier.
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%s%d", str, &i);
+}
+
+void do_not_diagnose(void) {
+ char str[32];
+
+ scanf("%s", str); // Not a numerical conversion
+ scanf("%*d"); // Assignment suppressed
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-err34-c.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,43 @@
+// RUN: %check_clang_tidy %s cert-err34-c %t
+
+typedef void * FILE;
+
+extern FILE *stdin;
+
+extern int fscanf(FILE * stream, const char * format, ...);
+extern int sscanf(const char * s, const char * format, ...);
+
+extern double atof(const char *nptr);
+extern int atoi(const char *nptr);
+extern long int atol(const char *nptr);
+extern long long int atoll(const char *nptr);
+
+namespace std {
+using ::FILE; using ::stdin;
+using ::fscanf; using ::sscanf;
+using ::atof; using ::atoi; using ::atol; using ::atoll;
+}
+
+void f1(const char *in) {
+ int i;
+ long long ll;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ std::sscanf(in, "%d", &i);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ std::fscanf(std::stdin, "%lld", &ll);
+}
+
+void f2(const char *in) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: 'atoi' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ int i = std::atoi(in); // to int
+ // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: 'atol' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ long l = std::atol(in); // to long
+
+ using namespace std;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'atoll' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ long long ll = atoll(in); // to long long
+ // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: 'atof' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c]
+ double d = atof(in); // to double
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-flp30-c.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-flp30-c.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-flp30-c.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-flp30-c.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy %s cert-flp30-c %t
+
+float g(void);
+
+void func(void) {
+ for (float x = 0.1f; x <= 1.0f; x += 0.1f) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: loop induction expression should not have floating-point type [cert-flp30-c]
+
+ float f = 1.0f;
+ for (; f > 0; --f) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: loop induction expression
+
+ for (;;g()) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: loop induction expression
+
+ for (int i = 0; i < 10; i += 1.0f) {}
+
+ for (int i = 0; i < 10; ++i) {}
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s cert-msc30-c %t
+
+extern int rand(void);
+int nonrand();
+
+int cTest() {
+ int i = rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness [cert-msc30-c]
+
+ int k = nonrand();
+
+ return 0;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-limited-randomness.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s cert-msc50-cpp %t
+
+int rand();
+int rand(int);
+
+namespace std {
+using ::rand;
+}
+
+namespace nonstd {
+ int rand();
+}
+
+void testFunction1() {
+ int i = std::rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness; use C++11 random library instead [cert-msc50-cpp]
+
+ int j = ::rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness; use C++11 random library instead [cert-msc50-cpp]
+
+ int k = rand(i);
+
+ int l = nonstd::rand();
+
+ int m = rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness; use C++11 random library instead [cert-msc50-cpp]
+}
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc32-c.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc32-c.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc32-c.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc32-c.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,27 @@
+// RUN: %check_clang_tidy %s cert-msc32-c %t -- -config="{CheckOptions: [{key: cert-msc32-c.DisallowedSeedTypes, value: 'some_type,time_t'}]}" -- -std=c99
+
+void srand(int seed);
+typedef int time_t;
+time_t time(time_t *t);
+
+void f() {
+ srand(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc32-c]
+
+ const int a = 1;
+ srand(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc32-c]
+
+ time_t t;
+ srand(time(&t)); // Disallowed seed type
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc32-c]
+}
+
+void g() {
+ typedef int user_t;
+ user_t a = 1;
+ srand(a);
+
+ int b = 1;
+ srand(b); // Can not evaluate as int
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc51-cpp.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc51-cpp.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc51-cpp.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-msc51-cpp.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,211 @@
+// RUN: %check_clang_tidy %s cert-msc51-cpp %t -- \
+// RUN: -config="{CheckOptions: [{key: cert-msc51-cpp.DisallowedSeedTypes, value: 'some_type,time_t'}]}"
+
+namespace std {
+
+void srand(int seed);
+
+template <class UIntType, UIntType a, UIntType c, UIntType m>
+struct linear_congruential_engine {
+ linear_congruential_engine(int _ = 0);
+ void seed(int _ = 0);
+};
+using default_random_engine = linear_congruential_engine<unsigned int, 1, 2, 3>;
+
+using size_t = int;
+template <class UIntType, size_t w, size_t n, size_t m, size_t r,
+ UIntType a, size_t u, UIntType d, size_t s,
+ UIntType b, size_t t,
+ UIntType c, size_t l, UIntType f>
+struct mersenne_twister_engine {
+ mersenne_twister_engine(int _ = 0);
+ void seed(int _ = 0);
+};
+using mt19937 = mersenne_twister_engine<unsigned int, 32, 624, 397, 21, 0x9908b0df, 11, 0xffffffff, 7, 0x9d2c5680, 15, 0xefc60000, 18, 1812433253>;
+
+template <class UIntType, size_t w, size_t s, size_t r>
+struct subtract_with_carry_engine {
+ subtract_with_carry_engine(int _ = 0);
+ void seed(int _ = 0);
+};
+using ranlux24_base = subtract_with_carry_engine<unsigned int, 24, 10, 24>;
+
+template <class Engine, size_t p, size_t r>
+struct discard_block_engine {
+ discard_block_engine();
+ discard_block_engine(int _);
+ void seed();
+ void seed(int _);
+};
+using ranlux24 = discard_block_engine<ranlux24_base, 223, 23>;
+
+template <class Engine, size_t w, class UIntType>
+struct independent_bits_engine {
+ independent_bits_engine();
+ independent_bits_engine(int _);
+ void seed();
+ void seed(int _);
+};
+using independent_bits = independent_bits_engine<ranlux24_base, 223, int>;
+
+template <class Engine, size_t k>
+struct shuffle_order_engine {
+ shuffle_order_engine();
+ shuffle_order_engine(int _);
+ void seed();
+ void seed(int _);
+};
+using shuffle_order = shuffle_order_engine<ranlux24_base, 223>;
+
+struct random_device {
+ random_device();
+ int operator()();
+};
+} // namespace std
+
+using time_t = unsigned int;
+time_t time(time_t *t);
+
+void f() {
+ const int seed = 2;
+ time_t t;
+
+ std::srand(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::srand(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::srand(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ // One instantiation for every engine
+ std::default_random_engine engine1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::default_random_engine engine2(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::default_random_engine engine3(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::default_random_engine engine4(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::mt19937 engine5;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::mt19937 engine6(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::mt19937 engine7(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::mt19937 engine8(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::ranlux24_base engine9;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24_base engine10(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24_base engine11(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24_base engine12(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::ranlux24 engine13;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24 engine14(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24 engine15(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24 engine16(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::independent_bits engine17;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::independent_bits engine18(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::independent_bits engine19(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::independent_bits engine20(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::shuffle_order engine21;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::shuffle_order engine22(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::shuffle_order engine23(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::shuffle_order engine24(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+}
+
+struct A {
+ A(int _ = 0);
+ void seed(int _ = 0);
+};
+
+void g() {
+ int n = 1;
+ std::default_random_engine engine1(n);
+ std::mt19937 engine2(n);
+ std::ranlux24_base engine3(n);
+ std::ranlux24 engine4(n);
+ std::independent_bits engine5(n);
+ std::shuffle_order engine6(n);
+
+ std::random_device dev;
+ std::default_random_engine engine7(dev());
+ std::mt19937 engine8(dev());
+ std::ranlux24_base engine9(dev());
+ std::ranlux24 engine10(dev());
+ std::independent_bits engine11(dev());
+ std::shuffle_order engine12(dev());
+
+ A a1;
+ A a2(1);
+ a1.seed();
+ a1.seed(1);
+ a1.seed(n);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop11-cpp.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop11-cpp.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop11-cpp.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop11-cpp.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy %s cert-oop11-cpp %t
+
+struct B {
+ B(B&&) noexcept = default;
+
+ B(const B &) = default;
+ B& operator=(const B&) = default;
+ ~B() {}
+};
+
+struct D {
+ B b;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: move constructor initializes class member by calling a copy constructor [cert-oop11-cpp]
+ D(D &&d) : b(d.b) {}
+
+ // This should not produce a diagnostic because it is not covered under
+ // the CERT guideline for OOP11-CPP. However, this will produce a diagnostic
+ // under performance-move-constructor-init.
+ D(B b) : b(b) {}
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop54-cpp.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop54-cpp.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop54-cpp.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-oop54-cpp.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,16 @@
+// RUN: %check_clang_tidy %s cert-oop54-cpp %t
+
+// Test whether bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField option is set correctly.
+class TrivialFields {
+public:
+ TrivialFields &operator=(const TrivialFields &object) {
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: operator=() does not handle self-assignment properly [cert-oop54-cpp]
+ return *this;
+ }
+
+private:
+ int m;
+ float f;
+ double d;
+ bool b;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-setlongjmp.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-setlongjmp.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-setlongjmp.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-setlongjmp.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s cert-err52-cpp %t
+
+typedef void *jmp_buf;
+extern int __setjmpimpl(jmp_buf);
+#define setjmp(x) __setjmpimpl(x)
+[[noreturn]] extern void longjmp(jmp_buf, int);
+
+namespace std {
+using ::jmp_buf;
+using ::longjmp;
+}
+
+static jmp_buf env;
+void g() {
+ std::longjmp(env, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead [cert-err52-cpp]
+ ::longjmp(env, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead
+ longjmp(env, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead
+}
+
+void f() {
+ (void)setjmp(env);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not call 'setjmp'; consider using exception handling instead
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-static-object-exception.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-static-object-exception.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-static-object-exception.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-static-object-exception.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,275 @@
+// RUN: clang-tidy %s -checks="-*,cert-err58-cpp" -- -std=c++17 -target x86_64-pc-linux-gnu \
+// RUN: | FileCheck %s -check-prefix=CHECK-EXCEPTIONS \
+// RUN: -implicit-check-not="{{warning|error}}:"
+// RUN: clang-tidy %s -checks="-*,cert-err58-cpp" -- -DNONEXCEPTIONS -fno-exceptions -std=c++17 -target x86_64-pc-linux-gnu \
+// RUN: | FileCheck %s -allow-empty -check-prefix=CHECK-NONEXCEPTIONS \
+// RUN: -implicit-check-not="{{warning|error}}:"
+
+struct S {
+ S() noexcept(false);
+};
+
+struct T {
+ T() noexcept;
+};
+
+struct U {
+ U() {}
+};
+
+struct V {
+ explicit V(const char *) {} // Can throw
+};
+
+struct Cleanup {
+ ~Cleanup() {}
+};
+
+struct W {
+ W(Cleanup c = {}) noexcept(false);
+};
+
+struct X {
+ X(S = {}) noexcept;
+};
+
+struct Y {
+ S s;
+};
+
+struct Z {
+ T t;
+};
+
+int f();
+int g() noexcept(false);
+int h() noexcept(true);
+
+struct UserConv_Bad {
+ operator int() noexcept(false);
+};
+
+struct UserConv_Good {
+ operator int() noexcept;
+};
+
+UserConv_Bad some_bad_func() noexcept;
+UserConv_Good some_good_func() noexcept;
+
+S s;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+T t; // ok
+U u;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+V v("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+W w;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+X x1(S{});
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'x1' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+X x2;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'x2' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+Y y;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'y' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 36:8: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+Z z;
+
+int i = f();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'i' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 44:5: note: possibly throwing function declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+int j = g();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'j' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 45:5: note: possibly throwing function declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+int k = h();
+int l = some_bad_func();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'l' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 49:3: note: possibly throwing function declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+int m = some_good_func();
+
+typedef decltype(sizeof(int)) size_t;
+inline void *operator new(size_t sz, void *here) noexcept { return here; }
+char n[sizeof(int)];
+int *o = new (n) int();
+int *p = new int();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'p' with static storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+
+thread_local S s3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local T t3; // ok
+thread_local U u3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local V v3("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local W w3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+
+void f(S s1, T t1, U u1, V v1, W w1) { // ok, ok, ok, ok, ok
+ S s2; // ok
+ T t2; // ok
+ U u2; // ok
+ V v2("v"); // ok
+ W w2; // ok
+
+ thread_local S s3; // ok
+ thread_local T t3; // ok
+ thread_local U u3; // ok
+ thread_local V v3("v"); // ok
+ thread_local W w3; // ok
+
+ static S s4; // ok
+ static T t4; // ok
+ static U u4; // ok
+ static V v4("v"); // ok
+ static W w4; // ok
+}
+
+namespace {
+S s;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+T t; // ok
+U u;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+V v("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+W w;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+
+thread_local S s3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local T t3; // ok
+thread_local U u3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local V v3("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local W w3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+}; // namespace
+
+class Statics {
+ static S s; // warn when initialized
+ static T t; // ok
+ static U u; // warn when initialized
+ static V v; // warn when initialized
+ static W w; // warn when initialized
+
+ void f(S s, T t, U u, V v) {
+ S s2; // ok
+ T t2; // ok
+ U u2; // ok
+ V v2("v"); // ok
+ W w2; // ok
+
+ thread_local S s3; // ok
+ thread_local T t3; // ok
+ thread_local U u3; // ok
+ thread_local V v3("v"); // ok
+ thread_local W w3; // ok
+
+ static S s4; // ok
+ static T t4; // ok
+ static U u4; // ok
+ static V v4("v"); // ok
+ static W w4; // ok
+ }
+};
+
+S Statics::s;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+T Statics::t;
+U Statics::u;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+V Statics::v("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+W Statics::w;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+
+#ifndef NONEXCEPTIONS
+namespace pr35457 {
+constexpr int foo(int x) { if (x <= 0) throw 12; return x; }
+
+constexpr int bar = foo(1); // OK
+// CHECK-EXCEPTIONS-NOT: warning: initialization of 'bar' with static storage
+int baz = foo(0); // Not OK; throws at runtime when exceptions are enabled.
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'baz' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: :[[@LINE-6]]:15: note: possibly throwing function declared here
+} // namespace pr35457
+#endif // NONEXCEPTIONS
+
+namespace pr39777 {
+struct S { S(); };
+struct T { T() noexcept; };
+
+auto Okay1 = []{ S s; };
+auto Okay2 = []{ (void)new int; };
+auto NotOkay1 = []{ S s; return 12; }(); // Because the lambda call is not noexcept
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay1' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: :[[@LINE-7]]:12: note: possibly throwing constructor declared here
+auto NotOkay2 = []() noexcept { S s; return 12; }(); // Because S::S() is not noexcept
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay2' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: :[[@LINE-10]]:12: note: possibly throwing constructor declared here
+auto Okay3 = []() noexcept { T t; return t; }();
+
+struct U {
+ U() noexcept;
+ auto getBadLambda() const noexcept {
+ return []{ S s; return s; };
+ }
+};
+auto Okay4 = []{ U u; return u.getBadLambda(); }();
+auto NotOkay3 = []() noexcept { U u; return u.getBadLambda(); }()(); // Because the lambda returned and called is not noexcept
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay3' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: :[[@LINE-6]]:12: note: possibly throwing function declared here
+
+#ifndef NONEXCEPTIONS
+struct Bad {
+ Bad() {
+ throw 12;
+ }
+};
+
+static auto NotOkay4 = [bad = Bad{}](){};
+// FIXME: the above should be diagnosed because the capture init can trigger
+// an exception when constructing the Bad object.
+#endif // NONEXCEPTIONS
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-throw-exception-type.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-throw-exception-type.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-throw-exception-type.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-throw-exception-type.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,129 @@
+// RUN: %check_clang_tidy -std=c++11,c++14 %s cert-err60-cpp %t -- -- -fcxx-exceptions
+// FIXME: Split off parts of this test that rely on dynamic exeption
+// specifications, and run this test in all language modes.
+
+struct S {};
+struct T : S {};
+struct U {
+ U() = default;
+ U(const U&) = default;
+};
+
+struct V {
+ V() = default;
+ V(const V&) noexcept;
+};
+
+struct W {
+ W() = default;
+ W(const W&) noexcept(false);
+};
+
+struct X {
+ X() = default;
+ X(const X&) {}
+};
+
+struct Y {
+ Y() = default;
+ Y(const Y&) throw();
+};
+
+struct Z {
+ Z() = default;
+ Z(const Z&) throw(int);
+};
+
+void g() noexcept(false);
+
+struct A {
+ A() = default;
+ A(const A&) noexcept(noexcept(g()));
+};
+
+struct B {
+ B() = default;
+ B(const B&) = default;
+ B(const A&) noexcept(false);
+};
+
+class C {
+ W M; // W is not no-throw copy constructible
+public:
+ C() = default;
+ C(const C&) = default;
+};
+
+struct D {
+ D() = default;
+ D(const D&) noexcept(false);
+ D(D&) noexcept(true);
+};
+
+struct E {
+ E() = default;
+ E(E&) noexcept(true);
+ E(const E&) noexcept(false);
+};
+
+struct Allocates {
+ int *x;
+ Allocates() : x(new int(0)) {}
+ Allocates(const Allocates &other) : x(new int(*other.x)) {}
+};
+
+struct OptionallyAllocates {
+ int *x;
+ OptionallyAllocates() : x(new int(0)) {}
+ OptionallyAllocates(const Allocates &other) noexcept(true) {
+ try {
+ x = new int(*other.x);
+ } catch (...) {
+ x = nullptr;
+ }
+ }
+};
+
+void f() {
+ throw 12; // ok
+ throw "test"; // ok
+ throw S(); // ok
+ throw T(); // ok
+ throw U(); // ok
+ throw V(); // ok
+ throw W(); // match, noexcept(false)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible [cert-err60-cpp]
+ throw X(); // match, no noexcept clause, nontrivial
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw Y(); // ok
+ throw Z(); // match, throw(int)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw A(); // match, noexcept(false)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw B(); // ok
+ throw C(); // match, C has a member variable that makes it throwing on copy
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw D(); // match, has throwing copy constructor
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw E(); // match, has throwing copy constructor
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw Allocates(); // match, copy constructor throws
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw OptionallyAllocates(); // ok
+}
+
+namespace PR25574 {
+struct B {
+ B(const B&) noexcept;
+};
+
+struct D : B {
+ D();
+ virtual ~D() noexcept;
+};
+
+template <typename T>
+void f() {
+ throw D();
+}
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-uppercase-literal-suffix-integer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-uppercase-literal-suffix-integer.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-uppercase-literal-suffix-integer.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-uppercase-literal-suffix-integer.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,159 @@
+// RUN: %check_clang_tidy %s cert-dcl16-c %t -- -- -I %S
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,cert-dcl16-c' -fix -- -I %S
+// RUN: clang-tidy %t.cpp -checks='-*,cert-dcl16-c' -warnings-as-errors='-*,cert-dcl16-c' -- -I %S
+
+#include "readability-uppercase-literal-suffix.h"
+
+void integer_suffix() {
+ static constexpr auto v0 = __LINE__; // synthetic
+ static_assert(v0 == 9 || v0 == 5, "");
+
+ static constexpr auto v1 = __cplusplus; // synthetic, long
+
+ static constexpr auto v2 = 1; // no literal
+ static_assert(is_same<decltype(v2), const int>::value, "");
+ static_assert(v2 == 1, "");
+
+ // Unsigned
+
+ static constexpr auto v3 = 1u;
+ static_assert(is_same<decltype(v3), const unsigned int>::value, "");
+ static_assert(v3 == 1, "");
+
+ static constexpr auto v4 = 1U; // OK.
+ static_assert(is_same<decltype(v4), const unsigned int>::value, "");
+ static_assert(v4 == 1, "");
+
+ // Long
+
+ static constexpr auto v5 = 1l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'l', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v5 = 1l;
+ // CHECK-MESSAGES-NEXT: ^~
+ // CHECK-MESSAGES-NEXT: {{^ *}}L{{$}}
+ // CHECK-FIXES: static constexpr auto v5 = 1L;
+ static_assert(is_same<decltype(v5), const long>::value, "");
+ static_assert(v5 == 1, "");
+
+ static constexpr auto v6 = 1L; // OK.
+ static_assert(is_same<decltype(v6), const long>::value, "");
+ static_assert(v6 == 1, "");
+
+ // Long Long
+
+ static constexpr auto v7 = 1ll;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: integer literal has suffix 'll', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v7 = 1ll;
+ // CHECK-MESSAGES-NEXT: ^~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}LL{{$}}
+ // CHECK-FIXES: static constexpr auto v7 = 1LL;
+ static_assert(is_same<decltype(v7), const long long>::value, "");
+ static_assert(v7 == 1, "");
+
+ static constexpr auto v8 = 1LL; // OK.
+ static_assert(is_same<decltype(v8), const long long>::value, "");
+ static_assert(v8 == 1, "");
+
+ // Unsigned Long
+
+ static constexpr auto v9 = 1ul;
+ static_assert(is_same<decltype(v9), const unsigned long>::value, "");
+ static_assert(v9 == 1, "");
+
+ static constexpr auto v10 = 1uL;
+ static_assert(is_same<decltype(v10), const unsigned long>::value, "");
+ static_assert(v10 == 1, "");
+
+ static constexpr auto v11 = 1Ul;
+ static_assert(is_same<decltype(v11), const unsigned long>::value, "");
+ static_assert(v11 == 1, "");
+
+ static constexpr auto v12 = 1UL; // OK.
+ static_assert(is_same<decltype(v12), const unsigned long>::value, "");
+ static_assert(v12 == 1, "");
+
+ // Long Unsigned
+
+ static constexpr auto v13 = 1lu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lu', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v13 = 1lu;
+ // CHECK-MESSAGES-NEXT: ^~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}LU{{$}}
+ // CHECK-FIXES: static constexpr auto v13 = 1LU;
+ static_assert(is_same<decltype(v13), const unsigned long>::value, "");
+ static_assert(v13 == 1, "");
+
+ static constexpr auto v14 = 1Lu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'Lu', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v14 = 1Lu;
+ // CHECK-MESSAGES-NEXT: ^~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}LU{{$}}
+ // CHECK-FIXES: static constexpr auto v14 = 1LU;
+ static_assert(is_same<decltype(v14), const unsigned long>::value, "");
+ static_assert(v14 == 1, "");
+
+ static constexpr auto v15 = 1lU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'lU', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v15 = 1lU;
+ // CHECK-MESSAGES-NEXT: ^~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}LU{{$}}
+ // CHECK-FIXES: static constexpr auto v15 = 1LU;
+ static_assert(is_same<decltype(v15), const unsigned long>::value, "");
+ static_assert(v15 == 1, "");
+
+ static constexpr auto v16 = 1LU; // OK.
+ static_assert(is_same<decltype(v16), const unsigned long>::value, "");
+ static_assert(v16 == 1, "");
+
+ // Unsigned Long Long
+
+ static constexpr auto v17 = 1ull;
+ static_assert(is_same<decltype(v17), const unsigned long long>::value, "");
+ static_assert(v17 == 1, "");
+
+ static constexpr auto v18 = 1uLL;
+ static_assert(is_same<decltype(v18), const unsigned long long>::value, "");
+ static_assert(v18 == 1, "");
+
+ static constexpr auto v19 = 1Ull;
+ static_assert(is_same<decltype(v19), const unsigned long long>::value, "");
+ static_assert(v19 == 1, "");
+
+ static constexpr auto v20 = 1ULL; // OK.
+ static_assert(is_same<decltype(v20), const unsigned long long>::value, "");
+ static_assert(v20 == 1, "");
+
+ // Long Long Unsigned
+
+ static constexpr auto v21 = 1llu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llu', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v21 = 1llu;
+ // CHECK-MESSAGES-NEXT: ^~~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}LLU{{$}}
+ // CHECK-FIXES: static constexpr auto v21 = 1LLU;
+ static_assert(is_same<decltype(v21), const unsigned long long>::value, "");
+ static_assert(v21 == 1, "");
+
+ static constexpr auto v22 = 1LLu;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'LLu', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v22 = 1LLu;
+ // CHECK-MESSAGES-NEXT: ^~~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}LLU{{$}}
+ // CHECK-FIXES: static constexpr auto v22 = 1LLU;
+ static_assert(is_same<decltype(v22), const unsigned long long>::value, "");
+ static_assert(v22 == 1, "");
+
+ static constexpr auto v23 = 1llU;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: integer literal has suffix 'llU', which is not uppercase
+ // CHECK-MESSAGES-NEXT: static constexpr auto v23 = 1llU;
+ // CHECK-MESSAGES-NEXT: ^~~~
+ // CHECK-MESSAGES-NEXT: {{^ *}}LLU{{$}}
+ // CHECK-FIXES: static constexpr auto v23 = 1LLU;
+ static_assert(is_same<decltype(v23), const unsigned long long>::value, "");
+ static_assert(v23 == 1, "");
+
+ static constexpr auto v24 = 1LLU; // OK.
+ static_assert(is_same<decltype(v24), const unsigned long long>::value, "");
+ static_assert(v24 == 1, "");
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cert-variadic-function-def.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cert-variadic-function-def.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cert-variadic-function-def.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cert-variadic-function-def.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s cert-dcl50-cpp %t
+
+// Variadic function definitions are diagnosed.
+void f1(int, ...) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: do not define a C-style variadic function; consider using a function parameter pack or currying instead [cert-dcl50-cpp]
+
+// Variadic function *declarations* are not diagnosed.
+void f2(int, ...); // ok
+
+// Function parameter packs are good, however.
+template <typename Arg, typename... Ts>
+void f3(Arg F, Ts... Rest) {}
+
+struct S {
+ void f(int, ...); // ok
+ void f1(int, ...) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: do not define a C-style variadic function; consider using a function parameter pack or currying instead
+};
+
+// Function definitions that are extern "C" are good.
+extern "C" void f4(int, ...) {} // ok
+extern "C" {
+ void f5(int, ...) {} // ok
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-avoid-goto.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-avoid-goto.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-avoid-goto.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-avoid-goto.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,139 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-goto %t
+
+void noop() {}
+
+int main() {
+ noop();
+ goto jump_to_me;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control
+ // CHECK-NOTES: [[@LINE+3]]:1: note: label defined here
+ noop();
+
+jump_to_me:;
+
+jump_backwards:;
+ noop();
+ goto jump_backwards;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control
+ // CHECK-NOTES: [[@LINE-4]]:1: note: label defined here
+
+ goto jump_in_line;
+ ;
+jump_in_line:;
+ // CHECK-NOTES: [[@LINE-3]]:3: warning: avoid using 'goto' for flow control
+ // CHECK-NOTES: [[@LINE-2]]:1: note: label defined here
+
+ // Test the GNU extension https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
+some_label:;
+ void *dynamic_label = &&some_label;
+
+ // FIXME: `IndirectGotoStmt` is not detected.
+ goto *dynamic_label;
+}
+
+void forward_jump_out_nested_loop() {
+ int array[] = {1, 2, 3, 4, 5};
+ for (int i = 0; i < 10; ++i) {
+ noop();
+ for (int j = 0; j < 10; ++j) {
+ noop();
+ if (i + j > 10)
+ goto early_exit1;
+ }
+ noop();
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ noop();
+ while (true) {
+ noop();
+ if (i > 5)
+ goto early_exit1;
+ }
+ noop();
+ }
+
+ for (auto value : array) {
+ noop();
+ for (auto number : array) {
+ noop();
+ if (number == 5)
+ goto early_exit1;
+ }
+ }
+
+ do {
+ noop();
+ do {
+ noop();
+ goto early_exit1;
+ } while (true);
+ } while (true);
+
+ do {
+ for (auto number : array) {
+ noop();
+ if (number == 2)
+ goto early_exit1;
+ }
+ } while (true);
+
+ // Jumping further results in error, because the variable declaration would
+ // be skipped.
+early_exit1:;
+
+ int i = 0;
+ while (true) {
+ noop();
+ while (true) {
+ noop();
+ if (i > 5)
+ goto early_exit2;
+ i++;
+ }
+ noop();
+ }
+
+ while (true) {
+ noop();
+ for (int j = 0; j < 10; ++j) {
+ noop();
+ if (j > 5)
+ goto early_exit2;
+ }
+ noop();
+ }
+
+ while (true) {
+ noop();
+ for (auto number : array) {
+ if (number == 1)
+ goto early_exit2;
+ noop();
+ }
+ }
+
+ while (true) {
+ noop();
+ do {
+ noop();
+ goto early_exit2;
+ } while (true);
+ }
+early_exit2:;
+}
+
+void jump_out_backwards() {
+
+before_the_loop:
+ noop();
+
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 0; j < 10; ++j) {
+ if (i * j > 80)
+ goto before_the_loop;
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: avoid using 'goto' for flow control
+ // CHECK-NOTES: [[@LINE-8]]:1: note: label defined here
+ }
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-init-variables.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,80 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-init-variables %t -- -- -fno-delayed-template-parsing
+
+// Ensure that function declarations are not changed.
+void some_func(int x, double d, bool b, const char *p);
+
+// Ensure that function arguments are not changed
+int identity_function(int x) {
+ return x;
+}
+
+int do_not_modify_me;
+
+static int should_not_be_initialized;
+extern int should_not_be_initialized2;
+
+typedef struct {
+ int unaltered1;
+ int unaltered2;
+} UnusedStruct;
+
+typedef int my_int_type;
+#define MACRO_INT int
+#define FULL_DECLARATION() int macrodecl;
+
+template <typename T>
+void template_test_function() {
+ T t;
+ int uninitialized;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'uninitialized' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} int uninitialized = 0;{{$}}
+}
+
+void init_unit_tests() {
+ int x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'x' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} int x = 0;{{$}}
+ my_int_type myint;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'myint' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} my_int_type myint = 0;{{$}}
+
+ MACRO_INT macroint;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: variable 'macroint' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} MACRO_INT macroint = 0;{{$}}
+ FULL_DECLARATION();
+
+ int x0 = 1, x1, x2 = 2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'x1' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} int x0 = 1, x1 = 0, x2 = 2;{{$}}
+ int y0, y1 = 1, y2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'y0' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: variable 'y2' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} int y0 = 0, y1 = 1, y2 = 0;{{$}}
+ int hasval = 42;
+
+ float f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: variable 'f' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} float f = NAN;{{$}}
+ float fval = 85.0;
+ double d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: variable 'd' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} double d = NAN;{{$}}
+ double dval = 99.0;
+
+ bool b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: variable 'b' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} bool b = 0;{{$}}
+ bool bval = true;
+
+ const char *ptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'ptr' is not initialized [cppcoreguidelines-init-variables]
+ // CHECK-FIXES: {{^}} const char *ptr = nullptr;{{$}}
+ const char *ptrval = "a string";
+
+ UnusedStruct u;
+
+ static int does_not_need_an_initializer;
+ extern int does_not_need_an_initializer2;
+ int parens(42);
+ int braces{42};
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-interfaces-global-init.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-interfaces-global-init.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-interfaces-global-init.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-interfaces-global-init.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,84 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-interfaces-global-init %t
+
+constexpr int makesInt() { return 3; }
+constexpr int takesInt(int i) { return i + 1; }
+constexpr int takesIntPtr(int *i) { return *i; }
+
+extern int ExternGlobal;
+static int GlobalScopeBadInit1 = ExternGlobal;
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit2 = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit3 = takesIntPtr(&ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit4 = 3 * (ExternGlobal + 2);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+
+namespace ns {
+static int NamespaceScope = makesInt();
+static int NamespaceScopeBadInit = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+
+struct A {
+ static int ClassScope;
+ static int ClassScopeBadInit;
+};
+
+int A::ClassScopeBadInit = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+
+static int FromClassBadInit = takesInt(A::ClassScope);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ClassScope'
+} // namespace ns
+
+// "const int B::I;" is fine, it just ODR-defines B::I. See [9.4.3] Static
+// members [class.static]. However the ODR-definitions are not in the right
+// order (C::I after C::J, see [3.6.2.3]).
+class B1 {
+ static const int I = 0;
+ static const int J = I;
+};
+const int B1::J;
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'I'
+const int B1::I;
+
+void f() {
+ // This is fine, it's executed after dynamic initialization occurs.
+ static int G = takesInt(ExternGlobal);
+}
+
+// Declaration then definition then usage is fine.
+extern int ExternGlobal2;
+extern int ExternGlobal2;
+int ExternGlobal2 = 123;
+static int GlobalScopeGoodInit1 = ExternGlobal2;
+
+
+// Defined global variables are fine:
+static int GlobalScope = makesInt();
+static int GlobalScopeGoodInit2 = takesInt(GlobalScope);
+static int GlobalScope2 = takesInt(ns::NamespaceScope);
+// Enums are fine.
+enum Enum { kEnumValue = 1 };
+static int GlobalScopeFromEnum = takesInt(kEnumValue);
+
+// Leave constexprs alone.
+extern constexpr int GlobalScopeConstexpr = makesInt();
+static constexpr int GlobalScopeConstexprOk =
+ takesInt(GlobalScopeConstexpr);
+
+// This is a pretty common instance: People are usually not using constexpr, but
+// this is what they should write:
+static constexpr const char kValue[] = "value";
+constexpr int Fingerprint(const char *value) { return 0; }
+static int kFingerprint = Fingerprint(kValue);
+
+// This is fine because the ODR-definitions are in the right order (C::J after
+// C::I).
+class B2 {
+ static const int I = 0;
+ static const int J = I;
+};
+const int B2::I;
+const int B2::J;
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-caps-only.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-caps-only.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-caps-only.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-caps-only.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-macro-usage %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-macro-usage.CheckCapsOnly, value: 1}]}' --
+
+#ifndef INCLUDE_GUARD
+#define INCLUDE_GUARD
+
+#define problematic_constant 0
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: macro definition does not define the macro name 'problematic_constant' using all uppercase characters
+
+#define problematic_function(x, y) ((a) > (b) ? (a) : (b))
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: macro definition does not define the macro name 'problematic_function' using all uppercase characters
+
+#define problematic_variadic(...) (__VA_ARGS__)
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: macro definition does not define the macro name 'problematic_variadic' using all uppercase characters
+//
+#define problematic_variadic2(x, ...) (__VA_ARGS__)
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: macro definition does not define the macro name 'problematic_variadic2' using all uppercase characters
+
+#define OKISH_CONSTANT 42
+#define OKISH_FUNCTION(x, y) ((a) > (b) ? (a) : (b))
+#define OKISH_VARIADIC(...) (__VA_ARGS__)
+
+#endif
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-command-line-macros.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-command-line-macros.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-command-line-macros.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-command-line-macros.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,8 @@
+// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- -- -D_ZZZ_IM_A_MACRO
+// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: 1}]}' -- -D_ZZZ_IM_A_MACRO
+// RUN: %check_clang_tidy -check-suffixes=NORMAL,CL %s cppcoreguidelines-macro-usage %t -- -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: 0}]}' -- -D_ZZZ_IM_A_MACRO
+
+// CHECK-MESSAGES-CL: warning: macro '_ZZZ_IM_A_MACRO' used to declare a constant; consider using a 'constexpr' constant
+
+#define PROBLEMATIC_CONSTANT 0
+// CHECK-MESSAGES-NORMAL: [[@LINE-1]]:9: warning: macro 'PROBLEMATIC_CONSTANT' used to declare a constant; consider using a 'constexpr' constant
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-custom.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-custom.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-custom.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-custom.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-macro-usage %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-macro-usage.AllowedRegexp, value: "DEBUG_*|TEST_*"}]}' --
+
+#ifndef INCLUDE_GUARD
+#define INCLUDE_GUARD
+
+#define PROBLEMATIC_CONSTANT 0
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: macro 'PROBLEMATIC_CONSTANT' used to declare a constant; consider using a 'constexpr' constant
+
+#define PROBLEMATIC_FUNCTION(x, y) ((a) > (b) ? (a) : (b))
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: function-like macro 'PROBLEMATIC_FUNCTION' used; consider a 'constexpr' template function
+
+#define PROBLEMATIC_VARIADIC(...) (__VA_ARGS__)
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: variadic macro 'PROBLEMATIC_VARIADIC' used; consider using a 'constexpr' variadic template function
+
+#define PROBLEMATIC_VARIADIC2(x, ...) (__VA_ARGS__)
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: variadic macro 'PROBLEMATIC_VARIADIC2' used; consider using a 'constexpr' variadic template function
+
+#define DEBUG_CONSTANT 0
+#define DEBUG_FUNCTION(x, y) ((a) > (b) ? (a) : (b))
+#define DEBUG_VARIADIC(...) (__VA_ARGS__)
+#define TEST_CONSTANT 0
+#define TEST_FUNCTION(x, y) ((a) > (b) ? (a) : (b))
+#define TEST_VARIADIC(...) (__VA_ARGS__)
+#define TEST_VARIADIC2(x, ...) (__VA_ARGS__)
+
+#endif
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-macro-usage.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-macro-usage %t -- -header-filter=.* -system-headers --
+
+#ifndef INCLUDE_GUARD
+#define INCLUDE_GUARD
+
+#define PROBLEMATIC_CONSTANT 0
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: macro 'PROBLEMATIC_CONSTANT' used to declare a constant; consider using a 'constexpr' constant
+
+#define PROBLEMATIC_FUNCTION(x, y) ((a) > (b) ? (a) : (b))
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: function-like macro 'PROBLEMATIC_FUNCTION' used; consider a 'constexpr' template function
+
+#define PROBLEMATIC_VARIADIC(...) (__VA_ARGS__)
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: variadic macro 'PROBLEMATIC_VARIADIC' used; consider using a 'constexpr' variadic template function
+
+#define PROBLEMATIC_VARIADIC2(x, ...) (__VA_ARGS__)
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: variadic macro 'PROBLEMATIC_VARIADIC2' used; consider using a 'constexpr' variadic template function
+
+#endif
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-long-is-32bits.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-long-is-32bits.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-long-is-32bits.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-long-is-32bits.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t \
+// RUN: -- -- -target x86_64-unknown-linux -m32
+
+static_assert(sizeof(int) * 8 == 32, "int is 32-bits");
+static_assert(sizeof(long) * 8 == 32, "long is 32-bits");
+static_assert(sizeof(long long) * 8 == 64, "long long is 64-bits");
+
+void narrow_integer_to_signed_integer_is_not_ok() {
+ int i; // i.e. int32_t
+ long l; // i.e. int32_t
+ long long ll; // i.e. int64_t
+
+ unsigned int ui; // i.e. uint32_t
+ unsigned long ul; // i.e. uint32_t
+ unsigned long long ull; // i.e. uint64_t
+
+ i = l; // int and long are the same type.
+ i = ll; // int64_t does not fit in an int32_t
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ ll = ul; // uint32_t fits into int64_t
+ ll = ull; // uint64_t does not fit in an int64_t
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned long long' to signed type 'long long' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-narrowingfloatingpoint-option.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-narrowingfloatingpoint-option.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-narrowingfloatingpoint-option.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-narrowingfloatingpoint-option.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t \
+// RUN: -- -- -target x86_64-unknown-linux -fsigned-char
+
+namespace floats {
+
+void narrow_constant_floating_point_to_int_not_ok(double d) {
+ int i = 0;
+ i += 0.5;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i *= 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i /= 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += (double)0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += 2.0;
+ i += 2.0f;
+}
+
+double operator"" _double(unsigned long long);
+
+float narrow_double_to_float_return() {
+ return 0.5;
+}
+
+void narrow_double_to_float_not_ok(double d) {
+ float f;
+ f = d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'double' to 'float' [cppcoreguidelines-narrowing-conversions]
+ f = 15_double;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'double' to 'float' [cppcoreguidelines-narrowing-conversions]
+ f += d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'double' to 'float' [cppcoreguidelines-narrowing-conversions]
+ f = narrow_double_to_float_return();
+}
+
+void narrow_fp_constants() {
+ float f;
+ f = 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+
+ f = __builtin_huge_valf(); // max float is not narrowing.
+ f = -__builtin_huge_valf(); // -max float is not narrowing.
+ f = __builtin_inff(); // float infinity is not narrowing.
+ f = __builtin_nanf("0"); // float NaN is not narrowing.
+
+ f = __builtin_huge_val(); // max double is not within-range of float.
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from constant 'double' to 'float' [cppcoreguidelines-narrowing-conversions]
+ f = -__builtin_huge_val(); // -max double is not within-range of float.
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from constant 'double' to 'float' [cppcoreguidelines-narrowing-conversions]
+ f = __builtin_inf(); // double infinity is not within-range of float.
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from constant 'double' to 'float' [cppcoreguidelines-narrowing-conversions]
+ f = __builtin_nan("0"); // double NaN is not narrowing.
+}
+
+} // namespace floats
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-pedanticmode-option.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-pedanticmode-option.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-pedanticmode-option.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-pedanticmode-option.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t \
+// RUN: -config="{CheckOptions: [ \
+// RUN: {key: "cppcoreguidelines-narrowing-conversions.PedanticMode", value: 1} \
+// RUN: ]}" \
+// RUN: -- -target x86_64-unknown-linux -fsigned-char
+
+namespace floats {
+
+void triggers_wrong_constant_type_warning(double d) {
+ int i = 0.0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: constant value should be of type of type 'int' instead of 'double' [cppcoreguidelines-narrowing-conversions]
+ i += 2.0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constant value should be of type of type 'int' instead of 'double' [cppcoreguidelines-narrowing-conversions]
+ i += 2.0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constant value should be of type of type 'int' instead of 'float' [cppcoreguidelines-narrowing-conversions]
+}
+
+void triggers_narrowing_warning_when_overflowing() {
+ unsigned short us = 65537.0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: narrowing conversion from constant 'double' to 'unsigned short' [cppcoreguidelines-narrowing-conversions]
+}
+
+} // namespace floats
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-unsigned-char.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-unsigned-char.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-unsigned-char.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-unsigned-char.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,83 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t \
+// RUN: -- -- -target x86_64-unknown-linux -funsigned-char
+
+void narrow_integer_to_unsigned_integer_is_ok() {
+ signed char sc;
+ short s;
+ int i;
+ long l;
+ long long ll;
+
+ char c;
+ unsigned short us;
+ unsigned int ui;
+ unsigned long ul;
+ unsigned long long ull;
+
+ ui = sc;
+ c = s;
+ c = i;
+ c = l;
+ c = ll;
+
+ c = c;
+ c = us;
+ c = ui;
+ c = ul;
+ c = ull;
+}
+
+void narrow_integer_to_signed_integer_is_not_ok() {
+ signed char sc;
+ short s;
+ int i;
+ long l;
+ long long ll;
+
+ char c;
+ unsigned short us;
+ unsigned int ui;
+ unsigned long ul;
+ unsigned long long ull;
+
+ sc = sc;
+ sc = s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'short' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ sc = i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'int' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ sc = l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'long' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ sc = ll;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'long long' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+
+ sc = c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'char' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ sc = us;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned short' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ sc = ui;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned int' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ sc = ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned long' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ sc = ull;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned long long' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+}
+
+void narrow_constant_to_unsigned_integer_is_ok() {
+ char c1 = -128; // unsigned dst type is well defined.
+ char c2 = 127; // unsigned dst type is well defined.
+ char c3 = -129; // unsigned dst type is well defined.
+ char c4 = 128; // unsigned dst type is well defined.
+ unsigned char uc1 = 0;
+ unsigned char uc2 = 255;
+ unsigned char uc3 = -1; // unsigned dst type is well defined.
+ unsigned char uc4 = 256; // unsigned dst type is well defined.
+ signed char sc = 128;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: narrowing conversion from constant value 128 (0x00000080) of type 'int' to signed type 'signed char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+}
+
+void narrow_conditional_operator_contant_to_unsigned_is_ok(bool b) {
+ // conversion to unsigned char type is well defined.
+ char c1 = b ? 1 : 0;
+ char c2 = b ? 1 : 256;
+ char c3 = b ? -1 : 0;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,346 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t \
+// RUN: -config="{CheckOptions: [ \
+// RUN: {key: "cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion", value: 0}, \
+// RUN: ]}" \
+// RUN: -- -target x86_64-unknown-linux -fsigned-char
+
+float ceil(float);
+namespace std {
+double ceil(double);
+long double floor(long double);
+} // namespace std
+
+namespace floats {
+
+struct ConvertsToFloat {
+ operator float() const { return 0.5f; }
+};
+
+float operator"" _float(unsigned long long);
+
+void narrow_fp_to_int_not_ok(double d) {
+ int i = 0;
+ i = d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = static_cast<float>(d);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = ConvertsToFloat();
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = 15_float;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += 0.5;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i *= 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i /= 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += (double)0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from constant 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += 2.0;
+ i += 2.0f;
+}
+
+double operator"" _double(unsigned long long);
+
+float narrow_double_to_float_return() {
+ return 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+}
+
+void narrow_double_to_float_ok(double d) {
+ float f;
+ f = d;
+ f = 15_double;
+}
+
+void narrow_fp_constants() {
+ float f;
+ f = 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+
+ f = __builtin_huge_valf(); // max float is not narrowing.
+ f = -__builtin_huge_valf(); // -max float is not narrowing.
+ f = __builtin_inff(); // float infinity is not narrowing.
+ f = __builtin_nanf("0"); // float NaN is not narrowing.
+
+ f = __builtin_huge_val(); // max double is not within-range of float.
+ f = -__builtin_huge_val(); // -max double is not within-range of float.
+ f = __builtin_inf(); // double infinity is not within-range of float.
+ f = __builtin_nan("0"); // double NaN is not narrowing.
+}
+
+void narrow_double_to_float_not_ok_binary_ops(double d) {
+ float f;
+ f += 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+ f += 2.0; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+ f *= 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+ f /= 0.5; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+ f += (double)0.5f; // [dcl.init.list] 7.2 : in-range fp constant to narrower float is not a narrowing.
+ f += d; // We do not warn about floating point narrowing by default.
+}
+
+void narrow_fp_constant_to_bool_not_ok() {
+ bool b1 = 1.0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant 'double' to 'bool' [cppcoreguidelines-narrowing-conversions]
+ bool b2 = 1.0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant 'float' to 'bool' [cppcoreguidelines-narrowing-conversions]
+}
+
+void narrow_integer_to_floating() {
+ {
+ long long ll; // 64 bits
+ float f = ll; // doesn't fit in 24 bits
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: narrowing conversion from 'long long' to 'float' [cppcoreguidelines-narrowing-conversions]
+ double d = ll; // doesn't fit in 53 bits.
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: narrowing conversion from 'long long' to 'double' [cppcoreguidelines-narrowing-conversions]
+ }
+ {
+ int i; // 32 bits
+ float f = i; // doesn't fit in 24 bits
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: narrowing conversion from 'int' to 'float' [cppcoreguidelines-narrowing-conversions]
+ double d = i; // fits in 53 bits.
+ }
+ {
+ short n1, n2;
+ float f = n1 + n2; // 'n1 + n2' is of type 'int' because of integer rules
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: narrowing conversion from 'int' to 'float' [cppcoreguidelines-narrowing-conversions]
+ }
+ {
+ short s; // 16 bits
+ float f = s; // fits in 24 bits
+ double d = s; // fits in 53 bits.
+ }
+}
+
+void narrow_integer_to_unsigned_integer_is_ok() {
+ char c;
+ short s;
+ int i;
+ long l;
+ long long ll;
+
+ unsigned char uc;
+ unsigned short us;
+ unsigned int ui;
+ unsigned long ul;
+ unsigned long long ull;
+
+ ui = c;
+ uc = s;
+ uc = i;
+ uc = l;
+ uc = ll;
+
+ uc = uc;
+ uc = us;
+ uc = ui;
+ uc = ul;
+ uc = ull;
+}
+
+void narrow_integer_to_signed_integer_is_not_ok() {
+ char c;
+ short s;
+ int i;
+ long l;
+ long long ll;
+
+ unsigned char uc;
+ unsigned short us;
+ unsigned int ui;
+ unsigned long ul;
+ unsigned long long ull;
+
+ c = c;
+ c = s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'short' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ c = i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ c = l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ c = ll;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+
+ c = uc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned char' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ c = us;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned short' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ c = ui;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ c = ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ c = ull;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long long' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+
+ i = c;
+ i = s;
+ i = i;
+ i = l;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ i = ll;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+
+ i = uc;
+ i = us;
+ i = ui;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned int' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ i = ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ i = ull;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'unsigned long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+
+ ll = c;
+ ll = s;
+ ll = i;
+ ll = l;
+ ll = ll;
+
+ ll = uc;
+ ll = us;
+ ll = ui;
+ ll = ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned long' to signed type 'long long' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ ll = ull;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: narrowing conversion from 'unsigned long long' to signed type 'long long' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+}
+
+void narrow_constant_to_unsigned_integer_is_ok() {
+ unsigned char uc1 = 0;
+ unsigned char uc2 = 255;
+ unsigned char uc3 = -1; // unsigned dst type is well defined.
+ unsigned char uc4 = 256; // unsigned dst type is well defined.
+ unsigned short us1 = 0;
+ unsigned short us2 = 65535;
+ unsigned short us3 = -1; // unsigned dst type is well defined.
+ unsigned short us4 = 65536; // unsigned dst type is well defined.
+}
+
+void narrow_constant_to_signed_integer_is_not_ok() {
+ char c1 = -128;
+ char c2 = 127;
+ char c3 = -129;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant value -129 (0xFFFFFF7F) of type 'int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ char c4 = 128;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: narrowing conversion from constant value 128 (0x00000080) of type 'int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+
+ short s1 = -32768;
+ short s2 = 32767;
+ short s3 = -32769;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: narrowing conversion from constant value -32769 (0xFFFF7FFF) of type 'int' to signed type 'short' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ short s4 = 32768;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: narrowing conversion from constant value 32768 (0x00008000) of type 'int' to signed type 'short' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+}
+
+void narrow_conditional_operator_contant_to_unsigned_is_ok(bool b) {
+ // conversion to unsigned dst type is well defined.
+ unsigned char c1 = b ? 1 : 0;
+ unsigned char c2 = b ? 1 : 256;
+ unsigned char c3 = b ? -1 : 0;
+}
+
+void narrow_conditional_operator_contant_to_signed_is_not_ok(bool b) {
+ char uc1 = b ? 1 : 0;
+ char uc2 = b ? 1 : 128;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: narrowing conversion from constant value 128 (0x00000080) of type 'int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ char uc3 = b ? -129 : 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: narrowing conversion from constant value -129 (0xFFFFFF7F) of type 'int' to signed type 'char' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ unsigned long long ysize;
+ long long mirror = b ? -1 : ysize - 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: narrowing conversion from constant value 18446744073709551615 (0xFFFFFFFFFFFFFFFF) of type 'unsigned long long' to signed type 'long long' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+ // CHECK-MESSAGES: :[[@LINE-2]]:37: warning: narrowing conversion from 'unsigned long long' to signed type 'long long' is implementation-defined [cppcoreguidelines-narrowing-conversions]
+}
+
+void narrow_constant_to_floating_point() {
+ float f_ok = 1ULL << 24; // fits in 24 bits mantissa.
+ float f_not_ok = (1ULL << 24) + 1ULL; // doesn't fit in 24 bits mantissa.
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: narrowing conversion from constant value 16777217 of type 'unsigned long long' to 'float' [cppcoreguidelines-narrowing-conversions]
+ double d_ok = 1ULL << 53; // fits in 53 bits mantissa.
+ double d_not_ok = (1ULL << 53) + 1ULL; // doesn't fit in 53 bits mantissa.
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: narrowing conversion from constant value 9007199254740993 of type 'unsigned long long' to 'double' [cppcoreguidelines-narrowing-conversions]
+}
+
+void casting_integer_to_bool_is_ok() {
+ int i;
+ while (i) {
+ }
+ for (; i;) {
+ }
+ if (i) {
+ }
+}
+
+void casting_float_to_bool_is_not_ok() {
+ float f;
+ while (f) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: narrowing conversion from 'float' to 'bool' [cppcoreguidelines-narrowing-conversions]
+ }
+ for (; f;) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: narrowing conversion from 'float' to 'bool' [cppcoreguidelines-narrowing-conversions]
+ }
+ if (f) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'bool' [cppcoreguidelines-narrowing-conversions]
+ }
+}
+
+void legitimate_comparison_do_not_warn(unsigned long long size) {
+ for (int i = 0; i < size; ++i) {
+ }
+}
+
+void ok(double d) {
+ int i = 0;
+ i = 1;
+ i = static_cast<int>(0.5);
+ i = static_cast<int>(d);
+ i = std::ceil(0.5);
+ i = ::std::floor(0.5);
+ {
+ using std::ceil;
+ i = ceil(0.5f);
+ }
+ i = ceil(0.5f);
+}
+
+void ok_binary_ops(double d) {
+ int i = 0;
+ i += 1;
+ i += static_cast<int>(0.5);
+ i += static_cast<int>(d);
+ i += (int)d;
+ i += std::ceil(0.5);
+ i += ::std::floor(0.5);
+ {
+ using std::ceil;
+ i += ceil(0.5f);
+ }
+ i += ceil(0.5f);
+}
+
+// We're bailing out in templates and macros.
+template <typename T1, typename T2>
+void f(T1 one, T2 two) {
+ one += two;
+}
+
+void template_context() {
+ f(1, 2);
+ f(1, .5f);
+ f(1, .5);
+ f(1, .5l);
+}
+
+#define DERP(i, j) (i += j)
+
+void macro_context() {
+ int i = 0;
+ DERP(i, 2);
+ DERP(i, .5f);
+ DERP(i, .5);
+ DERP(i, .5l);
+}
+
+} // namespace floats
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-custom.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-custom.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-custom.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-custom.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,59 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-no-malloc.Allocations, value: "::malloc;::align_malloc;::calloc"},\
+// RUN: {key: cppcoreguidelines-no-malloc.Reallocations, value: "::realloc;::align_realloc"},\
+// RUN: {key: cppcoreguidelines-no-malloc.Deallocations, value: "::free;::align_free"}]}' \
+// RUN: --
+
+using size_t = __SIZE_TYPE__;
+
+void *malloc(size_t size);
+void *align_malloc(size_t size, unsigned short aligmnent);
+void *calloc(size_t num, size_t size);
+void *realloc(void *ptr, size_t size);
+void *align_realloc(void *ptr, size_t size, unsigned short alignment);
+void free(void *ptr);
+void *align_free(void *ptr);
+
+void malloced_array() {
+ int *array0 = (int *)malloc(sizeof(int) * 20);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ int *zeroed = (int *)calloc(20, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ int *aligned = (int *)align_malloc(20 * sizeof(int), 16);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ // reallocation memory, std::vector shall be used
+ char *realloced = (char *)realloc(array0, 50 * sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
+
+ char *align_realloced = (char *)align_realloc(aligned, 50 * sizeof(int), 16);
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
+
+ // freeing memory the bad way
+ free(realloced);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+
+ align_free(align_realloced);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+
+ // check if a call to malloc as function argument is found as well
+ free(malloc(20));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+}
+
+/// newing an array is still not good, but not relevant to this checker
+void newed_array() {
+ int *new_array = new int[10]; // OK(1)
+}
+
+void arbitrary_call() {
+ // we dont want every function to raise the warning even if malloc is in the name
+ malloced_array(); // OK(2)
+
+ // completly unrelated function call to malloc
+ newed_array(); // OK(3)
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-no-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-no-functions.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-no-functions.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc-no-functions.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-no-malloc.Allocations, value: "::malloc"},\
+// RUN: {key: cppcoreguidelines-no-malloc.Reallocations, value: ""},\
+// RUN: {key: cppcoreguidelines-no-malloc.Deallocations, value: ""}]}' \
+// RUN: --
+
+// Just ensure, the check will not crash, when no functions shall be checked.
+
+using size_t = __SIZE_TYPE__;
+
+void *malloc(size_t size);
+
+void malloced_array() {
+ int *array0 = (int *)malloc(sizeof(int) * 20);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-no-malloc.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t
+
+using size_t = __SIZE_TYPE__;
+
+void *malloc(size_t size);
+void *calloc(size_t num, size_t size);
+void *realloc(void *ptr, size_t size);
+void free(void *ptr);
+
+void malloced_array() {
+ int *array0 = (int *)malloc(sizeof(int) * 20);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ int *zeroed = (int *)calloc(20, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ // reallocation memory, std::vector shall be used
+ char *realloced = (char *)realloc(array0, 50 * sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
+
+ // freeing memory the bad way
+ free(realloced);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+
+ // check if a call to malloc as function argument is found as well
+ free(malloc(20));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+}
+
+/// newing an array is still not good, but not relevant to this checker
+void newed_array() {
+ int *new_array = new int[10]; // OK(1)
+}
+
+void arbitrary_call() {
+ // we dont want every function to raise the warning even if malloc is in the name
+ malloced_array(); // OK(2)
+
+ // completly unrelated function call to malloc
+ newed_array(); // OK(3)
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-containers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-containers.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-containers.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-containers.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,62 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t
+
+namespace gsl {
+template <typename T>
+using owner = T;
+}
+
+namespace std {
+
+// Not actually a vector, but more a dynamic, fixed size array. Just to demonstrate
+// functionality or the lack of the same.
+template <typename T>
+class vector {
+public:
+ vector(unsigned long size, T val) : data{new T[size]}, size{size} {
+ for (unsigned long i = 0ul; i < size; ++i) {
+ data[i] = val;
+ }
+ }
+
+ T *begin() { return data; }
+ T *end() { return &data[size]; }
+ T &operator[](unsigned long index) { return data[index]; }
+
+private:
+ T *data;
+ unsigned long size;
+};
+
+} // namespace std
+
+// All of the following codesnippets should be valid with appropriate 'owner<>' anaylsis,
+// but currently the type information of 'gsl::owner<>' gets lost in typededuction.
+int main() {
+ std::vector<gsl::owner<int *>> OwnerStdVector(100, nullptr);
+
+ // Rangebased looping in resource vector.
+ for (auto *Element : OwnerStdVector) {
+ Element = new int(42);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+ }
+ for (auto *Element : OwnerStdVector) {
+ delete Element;
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // CHECK-NOTES: [[@LINE-3]]:8: note: variable declared here
+ }
+
+ // Indexbased looping in resource vector.
+ for (int i = 0; i < 100; ++i) {
+ OwnerStdVector[i] = new int(42);
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+ }
+ for (int i = 0; i < 100; ++i) {
+ delete OwnerStdVector[i];
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // CHECK-NOTES: [[@LINE-21]]:3: note: variable declared here
+ // A note gets emitted here pointing to the return value of the operator[] from the
+ // vector implementation. Maybe this is considered misleading.
+ }
+
+ return 0;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-legacy-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-legacy-functions.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-legacy-functions.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory-legacy-functions.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,194 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-owning-memory.LegacyResourceProducers, value: "::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile"}, \
+// RUN: {key: cppcoreguidelines-owning-memory.LegacyResourceConsumers, value: "::free;::realloc;::freopen;::fclose"}]}' \
+// RUN: -- -nostdlib -nostdinc++
+
+namespace gsl {
+template <class T>
+using owner = T;
+} // namespace gsl
+
+extern "C" {
+using size_t = decltype(sizeof(void*));
+using FILE = int;
+
+void *malloc(size_t ByteCount);
+void *aligned_alloc(size_t Alignment, size_t Size);
+void *calloc(size_t Count, size_t SizeSingle);
+void *realloc(void *Resource, size_t NewByteCount);
+void free(void *Resource);
+
+FILE *tmpfile(void);
+FILE *fopen(const char *filename, const char *mode);
+FILE *freopen(const char *filename, const char *mode, FILE *stream);
+void fclose(FILE *Resource);
+}
+
+namespace std {
+using ::FILE;
+using ::size_t;
+
+using ::fclose;
+using ::fopen;
+using ::freopen;
+using ::tmpfile;
+
+using ::aligned_alloc;
+using ::calloc;
+using ::free;
+using ::malloc;
+using ::realloc;
+} // namespace std
+
+void nonOwningCall(int *Resource, size_t Size) {}
+void nonOwningCall(FILE *Resource) {}
+
+void consumesResource(gsl::owner<int *> Resource, size_t Size) {}
+void consumesResource(gsl::owner<FILE *> Resource) {}
+
+void testNonCasted(void *Resource) {}
+
+void testNonCastedOwner(gsl::owner<void *> Resource) {}
+
+FILE *fileFactory1() { return ::fopen("new_file.txt", "w"); }
+// CHECK-MESSAGES: [[@LINE-1]]:24: warning: returning a newly created resource of type 'FILE *' (aka 'int *') or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+gsl::owner<FILE *> fileFactory2() { return std::fopen("new_file.txt", "w"); } // Ok
+
+int *arrayFactory1() { return (int *)std::malloc(100); }
+// CHECK-MESSAGES: [[@LINE-1]]:24: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+gsl::owner<int *> arrayFactory2() { return (int *)std::malloc(100); } // Ok
+void *dataFactory1() { return std::malloc(100); }
+// CHECK-MESSAGES: [[@LINE-1]]:24: warning: returning a newly created resource of type 'void *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+gsl::owner<void *> dataFactory2() { return std::malloc(100); } // Ok
+
+void test_resource_creators() {
+ const unsigned int ByteCount = 25 * sizeof(int);
+ int Bad = 42;
+
+ int *IntArray1 = (int *)std::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ int *IntArray2 = static_cast<int *>(std::malloc(ByteCount)); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ void *IntArray3 = std::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'void *' with a newly created 'gsl::owner<>'
+
+ int *IntArray4 = (int *)::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ int *IntArray5 = static_cast<int *>(::malloc(ByteCount)); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ void *IntArray6 = ::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'void *' with a newly created 'gsl::owner<>'
+
+ gsl::owner<int *> IntArray7 = (int *)malloc(ByteCount); // Ok
+ gsl::owner<void *> IntArray8 = malloc(ByteCount); // Ok
+
+ gsl::owner<int *> IntArray9 = &Bad;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ nonOwningCall((int *)malloc(ByteCount), 25);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+ nonOwningCall((int *)::malloc(ByteCount), 25);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+
+ consumesResource((int *)malloc(ByteCount), 25); // Ok
+ consumesResource((int *)::malloc(ByteCount), 25); // Ok
+
+ testNonCasted(malloc(ByteCount));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'void *' with a newly created 'gsl::owner<>'
+ testNonCastedOwner(gsl::owner<void *>(malloc(ByteCount))); // Ok
+ testNonCastedOwner(malloc(ByteCount)); // Ok
+
+ FILE *File1 = std::fopen("test_name.txt", "w+");
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ FILE *File2 = ::fopen("test_name.txt", "w+");
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+
+ gsl::owner<FILE *> File3 = ::fopen("test_name.txt", "w+"); // Ok
+
+ FILE *File4;
+ File4 = ::fopen("test_name.txt", "w+");
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'FILE *' (aka 'int *')
+
+ gsl::owner<FILE *> File5;
+ File5 = ::fopen("test_name.txt", "w+"); // Ok
+ File5 = File1;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'FILE *' (aka 'int *')
+
+ gsl::owner<FILE *> File6 = File1;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'FILE *' (aka 'int *')
+
+ FILE *File7 = tmpfile();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ gsl::owner<FILE *> File8 = tmpfile(); // Ok
+
+ nonOwningCall(::fopen("test_name.txt", "r"));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ nonOwningCall(std::fopen("test_name.txt", "r"));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+
+ consumesResource(::fopen("test_name.txt", "r")); // Ok
+
+ int *HeapPointer3 = (int *)aligned_alloc(16ul, 4ul * 32ul);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ gsl::owner<int *> HeapPointer4 = static_cast<int *>(aligned_alloc(16ul, 4ul * 32ul)); // Ok
+
+ void *HeapPointer5 = calloc(10ul, 4ul);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'void *' with a newly created 'gsl::owner<>'
+ gsl::owner<void *> HeapPointer6 = calloc(10ul, 4ul); // Ok
+}
+
+void test_legacy_consumers() {
+ int StackInteger = 42;
+
+ int *StackPointer = &StackInteger;
+ int *HeapPointer1 = (int *)malloc(100);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ gsl::owner<int *> HeapPointer2 = (int *)malloc(100);
+
+ std::free(StackPointer);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::free(HeapPointer1);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::free(HeapPointer2); // Ok
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+
+ // FIXME: the check complains about initialization of 'void *' with new created owner.
+ // This happens, because the argument of `free` is not marked as 'owner<>' (and cannot be),
+ // and the check will not figure out could be meant as owner.
+ // This property will probably never be fixed, because it is probably a rather rare
+ // use-case and 'owner<>' should be wrapped in RAII classes anyway!
+ std::free(std::malloc(100)); // Ok but silly :)
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: initializing non-owner argument of type 'void *' with a newly created 'gsl::owner<>'
+
+ // Demonstrate, that multi-argument functions are diagnosed as well.
+ std::realloc(StackPointer, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::realloc(HeapPointer1, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::realloc(HeapPointer2, 200); // Ok
+ std::realloc(std::malloc(100), 200); // Ok but silly
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: initializing non-owner argument of type 'void *' with a newly created 'gsl::owner<>'
+
+ fclose(fileFactory1());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ fclose(fileFactory2()); // Ok, same as FIXME with `free(malloc(100))` applies here
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: initializing non-owner argument of type 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+
+ gsl::owner<FILE *> File1 = fopen("testfile.txt", "r"); // Ok
+ FILE *File2 = freopen("testfile.txt", "w", File1);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:17: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ // FIXME: The warning for not passing and owner<> is a false positive since both the filename and the
+ // mode are not supposed to be owners but still pointers. The check is to coarse for
+ // this function. Maybe `freopen` gets special treatment.
+
+ gsl::owner<FILE *> File3 = freopen("testfile.txt", "w", File2); // Bad, File2 no owner
+ // CHECK-MESSAGES: [[@LINE-1]]:30: warning: calling legacy resource function without passing a 'gsl::owner<>'
+
+ FILE *TmpFile = tmpfile();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ FILE *File6 = freopen("testfile.txt", "w", TmpFile); // Bad, both return and argument
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:17: warning: calling legacy resource function without passing a 'gsl::owner<>'
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,391 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t
+
+namespace gsl {
+template <class T>
+using owner = T;
+} // namespace gsl
+
+template <typename T>
+class unique_ptr {
+public:
+ unique_ptr(gsl::owner<T> resource) : memory(resource) {}
+ unique_ptr(const unique_ptr<T> &) = default;
+
+ ~unique_ptr() { delete memory; }
+
+private:
+ gsl::owner<T> memory;
+};
+
+void takes_owner(gsl::owner<int *> owned_int) {
+}
+
+void takes_pointer(int *unowned_int) {
+}
+
+void takes_owner_and_more(int some_int, gsl::owner<int *> owned_int, float f) {
+}
+
+template <typename T>
+void takes_templated_owner(gsl::owner<T> owned_T) {
+}
+
+gsl::owner<int *> returns_owner1() { return gsl::owner<int *>(new int(42)); } // Ok
+gsl::owner<int *> returns_owner2() { return new int(42); } // Ok
+
+int *returns_no_owner1() { return nullptr; }
+int *returns_no_owner2() {
+ return new int(42);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+}
+int *returns_no_owner3() {
+ int *should_be_owner = new int(42);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ return should_be_owner;
+}
+int *returns_no_owner4() {
+ gsl::owner<int *> owner = new int(42);
+ return owner;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+}
+
+unique_ptr<int *> returns_no_owner5() {
+ return unique_ptr<int *>(new int(42)); // Ok
+}
+
+/// FIXME: CSA finds it, but the report is misleading. Ownersemantics can catch this
+/// by flow analysis similar to bugprone-use-after-move.
+void csa_not_finding_leak() {
+ gsl::owner<int *> o1 = new int(42); // Ok
+
+ gsl::owner<int *> o2 = o1; // Ok
+ o2 = new int(45); // conceptual leak, the memory from o1 is now leaked, since its considered moved in the guidelines
+
+ delete o2;
+ // actual leak occurs here, its found, but mixed
+ delete o1;
+}
+
+void test_assignment_and_initialization() {
+ int stack_int1 = 15;
+ int stack_int2;
+
+ gsl::owner<int *> owned_int1 = &stack_int1; // BAD
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int2;
+ owned_int2 = &stack_int2; // BAD since no owner, bad since uninitialized
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int3 = new int(42); // Good
+ owned_int3 = nullptr; // Good
+
+ gsl::owner<int *> owned_int4(nullptr); // Ok
+ owned_int4 = new int(42); // Good
+
+ gsl::owner<int *> owned_int5 = owned_int3; // Good
+
+ gsl::owner<int *> owned_int6{nullptr}; // Ok
+ owned_int6 = owned_int4; // Good
+
+ // FIXME:, flow analysis for the case of reassignment. Value must be released before
+ owned_int6 = owned_int3; // BAD, because reassignment without resource release
+
+ auto owned_int7 = returns_owner1(); // Bad, since type deduction eliminates the owner wrapper
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ const auto owned_int8 = returns_owner2(); // Bad, since type deduction eliminates the owner wrapper
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *const' with a newly created 'gsl::owner<>'
+ // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ gsl::owner<int *> owned_int9 = returns_owner1(); // Ok
+ int *unowned_int3 = returns_owner1(); // Bad
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+
+ gsl::owner<int *> owned_int10;
+ owned_int10 = returns_owner1(); // Ok
+
+ int *unowned_int4;
+ unowned_int4 = returns_owner1(); // Bad
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+
+ gsl::owner<int *> owned_int11 = returns_no_owner1(); // Bad since no owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int12;
+ owned_int12 = returns_no_owner1(); // Bad since no owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
+
+ int *unowned_int5 = returns_no_owner1(); // Ok
+ int *unowned_int6;
+ unowned_int6 = returns_no_owner1(); // Ok
+
+ int *unowned_int7 = new int(42); // Bad, since resource not assigned to an owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+
+ int *unowned_int8;
+ unowned_int8 = new int(42);
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+
+ gsl::owner<int *> owned_int13 = nullptr; // Ok
+}
+
+void test_deletion() {
+ gsl::owner<int *> owned_int1 = new int(42);
+ delete owned_int1; // Good
+
+ gsl::owner<int *> owned_int2 = new int[42];
+ delete[] owned_int2; // Good
+
+ int *unowned_int1 = new int(42); // BAD, since new creates and owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ delete unowned_int1; // BAD, since no owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here
+
+ int *unowned_int2 = new int[42]; // BAD, since new creates and owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ delete[] unowned_int2; // BAD since no owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here
+
+ delete new int(42); // Technically ok, but stupid
+ delete[] new int[42]; // Technically ok, but stupid
+}
+
+void test_owner_function_calls() {
+ int stack_int = 42;
+ int *unowned_int1 = &stack_int;
+ takes_owner(&stack_int); // BAD
+ // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+ takes_owner(unowned_int1); // BAD
+ // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int1 = new int(42);
+ takes_owner(owned_int1); // Ok
+
+ takes_owner_and_more(42, &stack_int, 42.0f); // BAD
+ // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+ takes_owner_and_more(42, unowned_int1, 42.0f); // BAD
+ // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+
+ takes_owner_and_more(42, new int(42), 42.0f); // Ok, since new is consumed by owner
+ takes_owner_and_more(42, owned_int1, 42.0f); // Ok, since owner as argument
+
+ takes_templated_owner(owned_int1); // Ok
+ takes_templated_owner(new int(42)); // Ok
+ takes_templated_owner(unowned_int1); // Bad
+ // CHECK-NOTES: [[@LINE-1]]:25: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+
+ takes_owner(returns_owner1()); // Ok
+ takes_owner(returns_no_owner1()); // BAD
+ // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+}
+
+void test_unowned_function_calls() {
+ int stack_int = 42;
+ int *unowned_int1 = &stack_int;
+ gsl::owner<int *> owned_int1 = new int(42);
+
+ takes_pointer(&stack_int); // Ok
+ takes_pointer(unowned_int1); // Ok
+ takes_pointer(owned_int1); // Ok
+ takes_pointer(new int(42)); // Bad, since new creates and owner
+ // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+
+ takes_pointer(returns_owner1()); // Bad
+ // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+
+ takes_pointer(returns_no_owner1()); // Ok
+}
+
+// FIXME: Typedefing owner<> to something else does not work.
+// This might be necessary for code already having a similar typedef like owner<> and
+// replacing it with owner<>. This might be the same problem as with templates.
+// The canonical type will ignore the owner<> alias, since its a typedef as well.
+//
+// Check, if owners hidden by typedef are handled the same as 'obvious' owners.
+#if 0
+using heap_int = gsl::owner<int *>;
+typedef gsl::owner<float *> heap_float;
+
+// This tests only a subset, assuming that the check will either see through the
+// typedef or not (it doesn't!).
+void test_typedefed_values() {
+ // Modern typedef.
+ int StackInt1 = 42;
+ heap_int HeapInt1 = &StackInt1;
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
+
+ //FIXME: Typedef not considered correctly here.
+ // heap_int HeapInt2 = new int(42); // Ok
+ takes_pointer(HeapInt1); // Ok
+ takes_owner(HeapInt1); // Ok
+
+ // Traditional typedef.
+ float StackFloat1 = 42.0f;
+ heap_float HeapFloat1 = &StackFloat1;
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'float *'
+
+ //FIXME: Typedef not considered correctly here.
+ // heap_float HeapFloat2 = new float(42.0f);
+ HeapFloat2 = HeapFloat1; // Ok
+}
+#endif
+
+struct ArbitraryClass {};
+struct ClassWithOwner { // Does not define destructor, necessary with owner
+ ClassWithOwner() : owner_var(nullptr) {} // Ok
+
+ ClassWithOwner(ArbitraryClass &other) : owner_var(&other) {}
+ // CHECK-NOTES: [[@LINE-1]]:43: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'ArbitraryClass *'
+
+ ClassWithOwner(gsl::owner<ArbitraryClass *> other) : owner_var(other) {} // Ok
+
+ ClassWithOwner(gsl::owner<ArbitraryClass *> data, int /* unused */) { // Ok
+ owner_var = data; // Ok
+ }
+
+ ClassWithOwner(ArbitraryClass *bad_data, int /* unused */, int /* unused */) {
+ owner_var = bad_data;
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
+ }
+
+ ClassWithOwner(ClassWithOwner &&other) : owner_var{other.owner_var} {} // Ok
+
+ ClassWithOwner &operator=(ClassWithOwner &&other) {
+ owner_var = other.owner_var; // Ok
+ return *this;
+ }
+
+ // Returning means, that the owner is "moved", so the class should not access this
+ // variable anymore after this method gets called.
+ gsl::owner<ArbitraryClass *> buggy_but_returns_owner() { return owner_var; }
+
+ gsl::owner<ArbitraryClass *> owner_var;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'ClassWithOwner' to implement a destructor to release the owned resource
+};
+
+class DefaultedDestructor { // Bad since default constructor with owner
+ ~DefaultedDestructor() = default; // Bad, since will not destroy the owner
+ gsl::owner<int *> Owner;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DefaultedDestructor' to implement a destructor to release the owned resource
+};
+
+struct DeletedDestructor {
+ ~DeletedDestructor() = delete;
+ gsl::owner<int *> Owner;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DeletedDestructor' to implement a destructor to release the owned resource
+};
+
+void test_class_with_owner() {
+ ArbitraryClass A;
+ ClassWithOwner C1; // Ok
+ ClassWithOwner C2{A}; // Bad, since the owner would be initialized with an non-owner, but catched in the class
+ ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok
+
+ const auto Owner1 = C3.buggy_but_returns_owner(); // BAD, deduces Owner1 to ArbitraryClass *const
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *const' with a newly created 'gsl::owner<>'
+ // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ auto Owner2 = C2.buggy_but_returns_owner(); // BAD, deduces Owner2 to ArbitraryClass *
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *' with a newly created 'gsl::owner<>'
+ // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ Owner2 = &A; // Ok, since type deduction did NOT result in owner<int*>
+
+ gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner
+ Owner3 = &A; // Bad, since assignment of non-owner to owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
+}
+
+template <typename T>
+struct HeapArray { // Ok, since destructor with owner
+ HeapArray() : _data(nullptr), size(0) {} // Ok
+ HeapArray(int size) : _data(new int[size]), size(size) {} // Ok
+ HeapArray(int size, T val) {
+ _data = new int[size]; // Ok
+ size = size;
+ for (auto i = 0u; i < size; ++i)
+ _data[i] = val; // Ok
+ }
+ HeapArray(int size, T val, int *problematic) : _data{problematic}, size(size) {} // Bad
+ // CHECK-NOTES: [[@LINE-1]]:50: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'void'
+ // FIXME: void is incorrect type, probably wrong thing matched
+
+ HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
+ other._data = nullptr; // Ok
+ other.size = 0;
+ }
+
+ HeapArray<T> &operator=(HeapArray<T> &&other) {
+ _data = other._data; // Ok, NOLINT warning here about bad types, why?
+ size = other.size;
+ return *this;
+ }
+
+ ~HeapArray() { delete[] _data; } // Ok
+
+ T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory
+
+ gsl::owner<T *> _data;
+ unsigned int size;
+};
+
+void test_inner_template() {
+ HeapArray<int> Array1;
+ HeapArray<int> Array2(100);
+ HeapArray<int> Array3(100, 0);
+ HeapArray<int> Array4(100, 0, nullptr);
+
+ Array1 = static_cast<HeapArray<int> &&>(Array2);
+ HeapArray<int> Array5(static_cast<HeapArray<int> &&>(Array3));
+
+ int *NonOwningPtr = Array1.data(); // Ok
+ gsl::owner<int *> OwningPtr = Array1.data(); // Bad, since it does not return the owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+}
+
+// FIXME: Typededuction removes the owner - wrapper, therefore gsl::owner can not be used
+// with Template classes like this. Is there a walkaround?
+template <typename T>
+struct TemplateValue {
+ TemplateValue() = default;
+ TemplateValue(T t) : val{t} {}
+
+ void setVal(const T &t) { val = t; }
+ const T getVal() const { return val; }
+
+ T val;
+};
+
+// FIXME: Same typededcution problems
+template <typename T>
+void template_function(T t) {
+ gsl::owner<int *> owner_t = t; // Probably bad, since type deduction still wrong
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'T'
+ // CHECK-NOTES: [[@LINE-2]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+}
+
+// FIXME: Same typededcution problems
+void test_templates() {
+ int stack_int = 42;
+ int *stack_ptr1 = &stack_int;
+
+ TemplateValue<gsl::owner<int *>> Owner0; // Ok, T should be owner, but is int*
+
+ TemplateValue<gsl::owner<int *>> Owner1(new int(42)); // Ok, T should be owner, but is int*
+ Owner1.setVal(&stack_int); // Bad since non-owner assignment
+ Owner1.setVal(stack_ptr1); // Bad since non-owner assignment
+ //Owner1.setVal(new int(42)); // Ok, but since type deduction is wrong, this one is considered harmful
+
+ int *stack_ptr2 = Owner1.getVal(); // Bad, initializing non-owner with owner
+
+ TemplateValue<int *> NonOwner1(new int(42)); // Bad, T is int *, hence dynamic memory to non-owner
+ gsl::owner<int *> IntOwner1 = NonOwner1.getVal(); // Bad, since owner initialized with non-owner
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ template_function(IntOwner1); // Ok, but not actually ok, since type deduction removes owner
+ template_function(stack_ptr1); // Bad, but type deduction gets it wrong
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,51 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-array-to-pointer-decay %t
+#include <stddef.h>
+
+namespace gsl {
+template <class T>
+class array_view {
+public:
+ template <class U, size_t N>
+ array_view(U (&arr)[N]);
+};
+}
+
+void pointerfun(int *p);
+void arrayfun(int p[]);
+void arrayviewfun(gsl::array_view<int> &p);
+size_t s();
+
+void f() {
+ int a[5];
+ pointerfun(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]
+ pointerfun((int *)a); // OK, explicit cast
+ arrayfun(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not implicitly decay an array into a pointer
+
+ pointerfun(a + s() - 10); // Convert to &a[g() - 10];
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not implicitly decay an array into a pointer
+
+ gsl::array_view<int> av(a);
+ arrayviewfun(av); // OK
+
+ int i = a[0]; // OK
+ int j = a[(1 + 2)];// OK
+ pointerfun(&a[0]); // OK
+
+ for (auto &e : a) // OK, iteration internally decays array to pointer
+ e = 1;
+}
+
+const char *g() {
+ return "clang"; // OK, decay string literal to pointer
+}
+const char *g2() {
+ return ("clang"); // OK, ParenExpr hides the literal-pointer decay
+}
+
+void f2(void *const *);
+void bug25362() {
+ void *a[2];
+ f2(static_cast<void *const*>(a)); // OK, explicit cast
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-c++03.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-c%2B%2B03.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-c++03.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-c++03.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy -std=c++98-or-later %s cppcoreguidelines-pro-bounds-constant-array-index %t
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+template <int index> struct B {
+ int get() {
+ // The next line used to crash the check (in C++03 mode only).
+ return x[index];
+ // CHECK-FIXES: return x[index];
+ }
+ int x[3];
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-gslheader.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-gslheader.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-gslheader.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index-gslheader.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,80 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t -- \
+// RUN: -config='{CheckOptions: [{key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader, value: "dir1/gslheader.h"}]}'
+// CHECK-FIXES: #include "dir1/gslheader.h"
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+ template<typename T, size_t N>
+ struct array {
+ T& operator[](size_t n);
+ T& at(size_t n);
+ };
+}
+
+
+namespace gsl {
+ template<class T, size_t N>
+ T& at( T(&a)[N], size_t index );
+
+ template<class T, size_t N>
+ T& at( std::array<T, N> &a, size_t index );
+}
+
+constexpr int const_index(int base) {
+ return base + 3;
+}
+
+void f(std::array<int, 10> a, int pos) {
+ a [ pos / 2 /*comment*/] = 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead [cppcoreguidelines-pro-bounds-constant-array-index]
+ // CHECK-FIXES: gsl::at(a, pos / 2 /*comment*/) = 1;
+ int j = a[pos - 1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+ // CHECK-FIXES: int j = gsl::at(a, pos - 1);
+
+ a.at(pos-1) = 2; // OK, at() instead of []
+ gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
+
+ a[-1] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
+ a[10] = 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
+
+ a[const_index(7)] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+void g() {
+ int a[10];
+ for (int i = 0; i < 10; ++i) {
+ a[i] = i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+ // CHECK-FIXES: gsl::at(a, i) = i;
+ gsl::at(a, i) = i; // OK, gsl::at() instead of []
+ }
+
+ a[-1] = 3; // flagged by clang-diagnostic-array-bounds
+ a[10] = 4; // flagged by clang-diagnostic-array-bounds
+ a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+struct S {
+ int& operator[](int i);
+};
+
+void customOperator() {
+ S s;
+ int i = 0;
+ s[i] = 3; // OK, custom operator
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-constant-array-index.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,87 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+ template<typename T, size_t N>
+ struct array {
+ T& operator[](size_t n);
+ T& at(size_t n);
+ };
+}
+
+
+namespace gsl {
+ template<class T, size_t N>
+ T& at( T(&a)[N], size_t index );
+
+ template<class T, size_t N>
+ T& at( std::array<T, N> &a, size_t index );
+}
+
+constexpr int const_index(int base) {
+ return base + 3;
+}
+
+void f(std::array<int, 10> a, int pos) {
+ a [ pos / 2 /*comment*/] = 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead [cppcoreguidelines-pro-bounds-constant-array-index]
+ int j = a[pos - 1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+
+ a.at(pos-1) = 2; // OK, at() instead of []
+ gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
+
+ a[-1] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
+ a[10] = 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
+
+ a[const_index(7)] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+void g() {
+ int a[10];
+ for (int i = 0; i < 10; ++i) {
+ a[i] = i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+ // CHECK-FIXES: gsl::at(a, i) = i;
+ gsl::at(a, i) = i; // OK, gsl::at() instead of []
+ }
+
+ a[-1] = 3; // flagged by clang-diagnostic-array-bounds
+ a[10] = 4; // flagged by clang-diagnostic-array-bounds
+ a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+struct S {
+ int& operator[](int i);
+};
+
+void customOperator() {
+ S s;
+ int i = 0;
+ s[i] = 3; // OK, custom operator
+}
+
+struct A {
+ // The compiler-generated copy constructor uses an ArraySubscriptExpr. Don't warn.
+ int x[3];
+};
+
+void use_A() {
+ // Force the compiler to generate a copy constructor.
+ A a;
+ A a2(a);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic-pr36489.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic-pr36489.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic-pr36489.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic-pr36489.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,53 @@
+// RUN: %check_clang_tidy -std=c++14-or-later %s cppcoreguidelines-pro-bounds-pointer-arithmetic %t
+
+// Fix PR36489 and detect auto-deduced value correctly.
+char *getPtr();
+auto getPtrAuto() { return getPtr(); }
+decltype(getPtr()) getPtrDeclType();
+decltype(auto) getPtrDeclTypeAuto() { return getPtr(); }
+auto getPtrWithTrailingReturnType() -> char *;
+
+void auto_deduction_binary() {
+ auto p1 = getPtr() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not use pointer arithmetic
+ auto p2 = getPtrAuto() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not use pointer arithmetic
+ auto p3 = getPtrWithTrailingReturnType() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: do not use pointer arithmetic
+ auto p4 = getPtr();
+ auto *p5 = getPtr();
+ p4 = p4 + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use pointer arithmetic
+ p5 = p5 + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use pointer arithmetic
+ auto p6 = getPtrDeclType() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: do not use pointer arithmetic
+ auto p7 = getPtrDeclTypeAuto() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: do not use pointer arithmetic
+ auto *p8 = getPtrDeclType() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: do not use pointer arithmetic
+ auto *p9 = getPtrDeclTypeAuto() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: do not use pointer arithmetic
+}
+
+void auto_deduction_subscript() {
+ char p1 = getPtr()[2];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p2 = getPtr()[3];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+
+ char p3 = getPtrAuto()[4];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p4 = getPtrAuto()[5];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+
+ char p5 = getPtrWithTrailingReturnType()[6];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p6 = getPtrWithTrailingReturnType()[7];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+
+ auto p7 = getPtrDeclType()[8];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p8 = getPtrDeclTypeAuto()[9];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,89 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-pointer-arithmetic %t
+
+enum E {
+ ENUM_LITERAL = 1
+};
+
+int i = 4;
+int j = 1;
+int *p = 0;
+int *q = 0;
+
+void fail() {
+ q = p + 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
+ p = q + i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+ p = q + ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+
+ q = p - 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+ p = q - i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+ p = q - ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+
+ p += 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ p += i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ p += ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+
+ q -= 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ q -= i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ q -= ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+
+ p++;
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
+ ++p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+
+ p--;
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
+ --p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+
+ i = p[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use pointer arithmetic
+}
+
+struct S {
+ operator int() const;
+};
+
+void f(S &s) {
+ int *i;
+ i = i + s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+}
+
+void f2(int i[]) {
+ i[1] = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+}
+
+void okay() {
+ int a[3];
+ i = a[2]; // OK, access to array
+
+ p = q;
+ p = &i;
+
+ i++;
+ ++i;
+ i--;
+ --i;
+ i += 1;
+ i -= 1;
+ i = j + 1;
+ i = j - 1;
+
+ auto diff = p - q; // OK, result is arithmetic
+
+ for(int ii : a) ; // OK, pointer arithmetic generated by compiler
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-const-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-const-cast.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-const-cast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-const-cast.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,6 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-const-cast %t
+
+const int *i;
+int *j;
+void f() { j = const_cast<int *>(i); }
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use const_cast [cppcoreguidelines-pro-type-const-cast]
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-cstyle-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-cstyle-cast.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-cstyle-cast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-cstyle-cast.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,141 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-cstyle-cast %t
+
+void reinterpretcast() {
+ int i = 0;
+ void *j;
+ j = (int*)j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
+}
+
+void constcast() {
+ int* i;
+ const int* j;
+ i = (int*)j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to cast away constness
+ j = (const int*)i; // OK, const added
+ (void)j; // OK, not a const_cast
+}
+
+void const_and_reinterpret() {
+ int* i;
+ const void* j;
+ i = (int*)j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to convert between unrelated types
+}
+
+class Base {
+};
+
+class Derived : public Base {
+};
+
+class Base2 {
+};
+
+class MultiDerived : public Base, public Base2 {
+};
+
+class PolymorphicBase {
+public:
+ virtual ~PolymorphicBase();
+};
+
+class PolymorphicDerived : public PolymorphicBase {
+};
+
+class PolymorphicMultiDerived : public Base, public PolymorphicBase {
+};
+
+void pointers() {
+
+ auto P0 = (Derived*)new Base();
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+
+ const Base* B0;
+ auto PC0 = (const Derived*)(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class
+
+ auto P1 = (Base*)new Derived(); // OK, upcast to a public base
+ auto P2 = (Base*)new MultiDerived(); // OK, upcast to a public base
+ auto P3 = (Base2*)new MultiDerived(); // OK, upcast to a public base
+}
+
+void pointers_polymorphic() {
+
+ auto PP0 = (PolymorphicDerived*)new PolymorphicBase();
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto PP0 = dynamic_cast<PolymorphicDerived*>(new PolymorphicBase());
+
+ const PolymorphicBase* B0;
+ auto PPC0 = (const PolymorphicDerived*)B0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto PPC0 = dynamic_cast<const PolymorphicDerived*>(B0);
+
+
+ auto B1 = (PolymorphicBase*)new PolymorphicDerived(); // OK, upcast to a public base
+ auto B2 = (PolymorphicBase*)new PolymorphicMultiDerived(); // OK, upcast to a public base
+ auto B3 = (Base*)new PolymorphicMultiDerived(); // OK, upcast to a public base
+}
+
+void arrays() {
+ Base ArrayOfBase[10];
+ auto A0 = (Derived*)ArrayOfBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+}
+
+void arrays_polymorphic() {
+ PolymorphicBase ArrayOfPolymorphicBase[10];
+ auto AP0 = (PolymorphicDerived*)ArrayOfPolymorphicBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto AP0 = dynamic_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
+}
+
+void references() {
+ Base B0;
+ auto R0 = (Derived&)B0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+ Base& RefToBase = B0;
+ auto R1 = (Derived&)RefToBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+
+ const Base& ConstRefToBase = B0;
+ auto RC1 = (const Derived&)ConstRefToBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class
+
+
+ Derived RD1;
+ auto R2 = (Base&)RD1; // OK, upcast to a public base
+}
+
+void references_polymorphic() {
+ PolymorphicBase B0;
+ auto RP0 = (PolymorphicDerived&)B0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RP0 = dynamic_cast<PolymorphicDerived&>(B0);
+
+ PolymorphicBase& RefToPolymorphicBase = B0;
+ auto RP1 = (PolymorphicDerived&)RefToPolymorphicBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RP1 = dynamic_cast<PolymorphicDerived&>(RefToPolymorphicBase);
+
+ const PolymorphicBase& ConstRefToPolymorphicBase = B0;
+ auto RPC2 = (const PolymorphicDerived&)(ConstRefToPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RPC2 = dynamic_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
+
+ PolymorphicDerived d1;
+ auto RP2 = (PolymorphicBase&)d1; // OK, upcast to a public base
+}
+
+template<class B, class D>
+void templ() {
+ auto B0 = (B*)new D();
+}
+
+void templ_bad_call() {
+ templ<Derived, Base>(); //FIXME: this should trigger a warning
+}
+
+void templ_good_call() {
+ templ<Base, Derived>(); // OK, upcast to a public base
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx2a.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx2a.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx2a.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx2a.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++2a %s cppcoreguidelines-pro-type-member-init %t -- -- -fno-delayed-template-parsing
+
+struct PositiveBitfieldMember {
+ PositiveBitfieldMember() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ unsigned F : 5;
+ // CHECK-FIXES: unsigned F : 5{};
+};
+
+struct NegativeUnnamedBitfieldMember {
+ NegativeUnnamedBitfieldMember() {}
+ unsigned : 5;
+};
+
+struct NegativeInitializedBitfieldMembers {
+ NegativeInitializedBitfieldMembers() : F(3) { G = 2; }
+ unsigned F : 5;
+ unsigned G : 5;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx98.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx98.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx98.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-cxx98.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,116 @@
+// RUN: %check_clang_tidy -std=c++98 %s cppcoreguidelines-pro-type-member-init %t -- -- -fno-delayed-template-parsing
+
+struct PositiveFieldBeforeConstructor {
+ int F;
+ PositiveFieldBeforeConstructor() /* some comment */ {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {}
+};
+
+struct PositiveFieldAfterConstructor {
+ PositiveFieldAfterConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G, H
+ // CHECK-FIXES: PositiveFieldAfterConstructor() : F(), G(), H() {}
+ int F;
+ bool G /* with comment */;
+ int *H;
+ PositiveFieldBeforeConstructor IgnoredField;
+};
+
+struct PositiveSeparateDefinition {
+ PositiveSeparateDefinition();
+ int F;
+};
+
+PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() : F() {}
+
+struct PositiveMixedFieldOrder {
+ PositiveMixedFieldOrder() : /* some comment */ J(0), L(0), M(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: I, K, N
+ // CHECK-FIXES: PositiveMixedFieldOrder() : I(), /* some comment */ J(0), K(), L(0), M(0), N() {}
+ int I;
+ int J;
+ int K;
+ int L;
+ int M;
+ int N;
+};
+
+struct PositiveAfterBaseInitializer : public PositiveMixedFieldOrder {
+ PositiveAfterBaseInitializer() : PositiveMixedFieldOrder() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ // CHECK-FIXES: PositiveAfterBaseInitializer() : PositiveMixedFieldOrder(), F() {}
+ int F;
+};
+
+struct NegativeFieldInitialized {
+ int F;
+
+ NegativeFieldInitialized() : F() {}
+};
+
+struct NegativeFieldInitializedInDefinition {
+ int F;
+
+ NegativeFieldInitializedInDefinition();
+};
+
+NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {}
+
+struct NegativeInitializedInBody {
+ NegativeInitializedInBody() { I = 0; }
+ int I;
+};
+
+struct NegativeAggregateType {
+ int X;
+ int Y;
+ int Z;
+};
+
+struct TrivialType {
+ int X;
+ int Y;
+};
+
+struct PositiveUninitializedBaseOrdering : public NegativeAggregateType,
+ public TrivialType {
+ PositiveUninitializedBaseOrdering() : NegativeAggregateType(), TrivialType(), B() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering() : NegativeAggregateType(), TrivialType(), A(), B() {}
+
+ // This is somewhat pathological with the base class initializer at the end...
+ PositiveUninitializedBaseOrdering(int) : B(), TrivialType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(int) : B(), NegativeAggregateType(), TrivialType(), A() {}
+
+ PositiveUninitializedBaseOrdering(float) : NegativeAggregateType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: TrivialType
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: constructor does not initialize these fields: B
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(float) : NegativeAggregateType(), TrivialType(), A(), B() {}
+
+ int A, B;
+};
+
+template <class T>
+class PositiveTemplateBase : T {
+public:
+ PositiveTemplateBase() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: X
+ // CHECK-FIXES: PositiveTemplateBase() : X() {}
+
+ int X;
+};
+
+class PositiveIndirectMember {
+ struct {
+ int *A;
+ };
+
+ PositiveIndirectMember() : A() {}
+ PositiveIndirectMember(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A
+ // CHECK-FIXES: PositiveIndirectMember(int) : A() {}
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-delayed.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-delayed.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-delayed.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-delayed.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -fdelayed-template-parsing
+
+template <class T>
+struct PositiveFieldBeforeConstructor {
+ int F;
+ bool G /* with comment */;
+ int *H;
+ PositiveFieldBeforeConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G, H
+};
+// Explicit instantiation.
+template class PositiveFieldBeforeConstructor<int>;
+
+template <class T>
+struct PositiveFieldAfterConstructor {
+ PositiveFieldAfterConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G, H
+ int F;
+ bool G /* with comment */;
+ int *H;
+};
+// Explicit instantiation.
+template class PositiveFieldAfterConstructor<int>;
+
+// This declaration isn't used and won't be parsed 'delayed-template-parsing'.
+// The body of the declaration is 'null' and may cause crash if not handled
+// properly by checkers.
+template <class T>
+struct UnusedDelayedConstructor {
+ UnusedDelayedConstructor() {}
+ int F;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-no-crash.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-no-crash.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-no-crash.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-no-crash.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,7 @@
+// RUN: %check_clang_tidy -expect-clang-tidy-error %s cppcoreguidelines-pro-type-member-init %t
+
+struct X {
+ X x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: error: field has incomplete type 'X' [clang-diagnostic-error]
+ int a = 10;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-use-assignment.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-use-assignment.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-use-assignment.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init-use-assignment.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -config="{CheckOptions: [{key: "cppcoreguidelines-pro-type-member-init.UseAssignment", value: 1}]}" -- -fsigned-char
+
+struct T {
+ int i;
+};
+
+struct S {
+ bool b;
+ // CHECK-FIXES: bool b = false;
+ char c;
+ // CHECK-FIXES: char c = 0;
+ signed char sc;
+ // CHECK-FIXES: signed char sc = 0;
+ unsigned char uc;
+ // CHECK-FIXES: unsigned char uc = 0U;
+ int i;
+ // CHECK-FIXES: int i = 0;
+ unsigned u;
+ // CHECK-FIXES: unsigned u = 0U;
+ long l;
+ // CHECK-FIXES: long l = 0L;
+ unsigned long ul;
+ // CHECK-FIXES: unsigned long ul = 0UL;
+ long long ll;
+ // CHECK-FIXES: long long ll = 0LL;
+ unsigned long long ull;
+ // CHECK-FIXES: unsigned long long ull = 0ULL;
+ float f;
+ // CHECK-FIXES: float f = 0.0F;
+ double d;
+ // CHECK-FIXES: double d = 0.0;
+ long double ld;
+ // CHECK-FIXES: double ld = 0.0L;
+ int *ptr;
+ // CHECK-FIXES: int *ptr = nullptr;
+ T t;
+ // CHECK-FIXES: T t{};
+ S() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields:
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-member-init.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,503 @@
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s cppcoreguidelines-pro-type-member-init %t -- -- -fno-delayed-template-parsing
+// FIXME: Fix the checker to work in C++2a mode.
+
+struct PositiveFieldBeforeConstructor {
+ int F;
+ // CHECK-FIXES: int F{};
+ PositiveFieldBeforeConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ // CHECK-FIXES: PositiveFieldBeforeConstructor() {}
+};
+
+struct PositiveFieldAfterConstructor {
+ PositiveFieldAfterConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G
+ // CHECK-FIXES: PositiveFieldAfterConstructor() {}
+ int F;
+ // CHECK-FIXES: int F{};
+ bool G /* with comment */;
+ // CHECK-FIXES: bool G{} /* with comment */;
+ PositiveFieldBeforeConstructor IgnoredField;
+};
+
+struct PositiveSeparateDefinition {
+ PositiveSeparateDefinition();
+ int F;
+ // CHECK-FIXES: int F{};
+};
+
+PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+
+struct PositiveMixedFieldOrder {
+ PositiveMixedFieldOrder() : J(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: I, K
+ // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {}
+ int I;
+ // CHECK-FIXES: int I{};
+ int J;
+ int K;
+ // CHECK-FIXES: int K{};
+};
+
+template <typename T>
+struct Template {
+ Template() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ int F;
+ // CHECK-FIXES: int F{};
+ T T1;
+ // CHECK-FIXES: T T1;
+};
+
+void instantiate() {
+ Template<int> TInt;
+}
+
+struct NegativeFieldInitialized {
+ int F;
+
+ NegativeFieldInitialized() : F() {}
+};
+
+struct NegativeFieldInitializedInDefinition {
+ int F;
+
+ NegativeFieldInitializedInDefinition();
+};
+NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {}
+
+struct NegativeInClassInitialized {
+ int F = 0;
+
+ NegativeInClassInitialized() {}
+};
+
+struct NegativeInClassInitializedDefaulted {
+ int F = 0;
+ NegativeInClassInitializedDefaulted() = default;
+};
+
+struct NegativeConstructorDelegated {
+ int F;
+
+ NegativeConstructorDelegated(int F) : F(F) {}
+ NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {}
+};
+
+struct NegativeInitializedInBody {
+ NegativeInitializedInBody() { I = 0; }
+ int I;
+};
+
+struct A {};
+template <class> class AA;
+template <class T> class NegativeTemplateConstructor {
+ NegativeTemplateConstructor(const AA<T> &, A) {}
+ bool Bool{false};
+ // CHECK-FIXES: bool Bool{false};
+};
+
+#define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \
+ struct UninitializedField##FIELD { \
+ UninitializedField##FIELD() {} \
+ int FIELD; \
+ }; \
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int FIELD;
+
+UNINITIALIZED_FIELD_IN_MACRO_BODY(F);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+UNINITIALIZED_FIELD_IN_MACRO_BODY(G);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: G
+
+#define UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(ARGUMENT) \
+ ARGUMENT
+
+UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(struct UninitializedFieldInMacroArg {
+ UninitializedFieldInMacroArg() {}
+ int Field;
+});
+// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: constructor does not initialize these fields: Field
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int Field;
+
+struct NegativeAggregateType {
+ int X;
+ int Y;
+ int Z;
+};
+
+struct PositiveTrivialType {
+ PositiveTrivialType() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+
+ NegativeAggregateType F;
+ // CHECK-FIXES: NegativeAggregateType F{};
+};
+
+struct NegativeNonTrivialType {
+ PositiveTrivialType F;
+};
+
+static void PositiveUninitializedTrivialType() {
+ NegativeAggregateType X;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'X'
+ // CHECK-FIXES: NegativeAggregateType X{};
+
+ NegativeAggregateType A[10]; // Don't warn because this isn't an object type.
+}
+
+static void NegativeInitializedTrivialType() {
+ NegativeAggregateType X{};
+ NegativeAggregateType Y = {};
+ NegativeAggregateType Z = NegativeAggregateType();
+ NegativeAggregateType A[10]{};
+ NegativeAggregateType B[10] = {};
+ int C; // No need to initialize this because we don't have a constructor.
+ int D[8];
+ NegativeAggregateType E = {0, 1, 2};
+ NegativeAggregateType F({});
+}
+
+struct NonTrivialType {
+ NonTrivialType() = default;
+ NonTrivialType(const NonTrivialType &RHS) : X(RHS.X), Y(RHS.Y) {}
+
+ int X;
+ int Y;
+};
+
+static void PositiveNonTrivialTypeWithCopyConstructor() {
+ NonTrivialType T;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'T'
+ // CHECK-FIXES: NonTrivialType T{};
+
+ NonTrivialType A[8];
+ // Don't warn because this isn't an object type
+}
+
+struct ComplexNonTrivialType {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: Y
+ NegativeFieldInitialized X;
+ int Y;
+ // CHECK-FIXES: int Y{};
+};
+
+static void PositiveComplexNonTrivialType() {
+ ComplexNonTrivialType T;
+}
+
+struct NegativeStaticMember {
+ static NonTrivialType X;
+ static NonTrivialType Y;
+ static constexpr NonTrivialType Z{};
+};
+
+NonTrivialType NegativeStaticMember::X;
+NonTrivialType NegativeStaticMember::Y{};
+
+struct PositiveMultipleConstructors {
+ PositiveMultipleConstructors() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B
+
+ PositiveMultipleConstructors(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B
+
+ PositiveMultipleConstructors(const PositiveMultipleConstructors &) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B
+
+ // FIXME: The fix-its here collide providing an erroneous fix
+ int A, B;
+ // CHECK-FIXES: int A{}{}{}, B{}{}{};
+};
+
+typedef struct {
+ int Member;
+} CStyleStruct;
+
+struct PositiveUninitializedBase : public NegativeAggregateType, CStyleStruct {
+ PositiveUninitializedBase() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType, CStyleStruct
+ // CHECK-FIXES: PositiveUninitializedBase() : NegativeAggregateType(), CStyleStruct() {}
+};
+
+struct PositiveUninitializedBaseOrdering : public NegativeAggregateType,
+ public NonTrivialType {
+ PositiveUninitializedBaseOrdering() : B() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType, NonTrivialType
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: constructor does not initialize these fields: A
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering() : NegativeAggregateType(), NonTrivialType(), B() {}
+
+ // This is somewhat pathological with the base class initializer at the end...
+ PositiveUninitializedBaseOrdering(int) : B(), NonTrivialType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(int) : B(), NegativeAggregateType(), NonTrivialType(), A() {}
+
+ PositiveUninitializedBaseOrdering(float) : B(), NegativeAggregateType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NonTrivialType
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(float) : B(), NegativeAggregateType(), NonTrivialType(), A() {}
+
+ int A, B;
+ // CHECK-FIXES: int A{}, B;
+};
+
+// We shouldn't need to initialize anything because PositiveUninitializedBase
+// has a user-defined constructor.
+struct NegativeUninitializedBase : public PositiveUninitializedBase {
+ NegativeUninitializedBase() {}
+};
+
+struct InheritedAggregate : public NegativeAggregateType {
+ int F;
+};
+
+static InheritedAggregate NegativeGlobal;
+
+enum TestEnum {
+ A,
+ B,
+ C
+};
+
+enum class TestScopedEnum {
+ A,
+ B,
+ C
+};
+
+struct PositiveEnumType {
+ PositiveEnumType() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: X, Y
+ // No proposed fixes, as we don't know whether value initialization for these
+ // enums really makes sense.
+
+ TestEnum X;
+ TestScopedEnum Y;
+};
+
+extern "C" {
+struct NegativeCStruct {
+ int X, Y, Z;
+};
+
+static void PositiveCStructVariable() {
+ NegativeCStruct X;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'X'
+ // CHECK-FIXES: NegativeCStruct X{};
+}
+}
+
+static void NegativeStaticVariable() {
+ static NegativeCStruct S;
+ (void)S;
+}
+
+union NegativeUnionInClass {
+ NegativeUnionInClass() {} // No message as a union can only initialize one member.
+ int X = 0;
+ float Y;
+};
+
+union PositiveUnion {
+ PositiveUnion() : X() {} // No message as a union can only initialize one member.
+ PositiveUnion(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: union constructor should initialize one of these fields: X, Y
+
+ int X;
+ // CHECK-FIXES: int X{};
+
+ // Make sure we don't give Y an initializer.
+ float Y;
+ // CHECK-FIXES-NOT: float Y{};
+};
+
+union PositiveUnionReversed {
+ PositiveUnionReversed() : X() {} // No message as a union can only initialize one member.
+ PositiveUnionReversed(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: union constructor should initialize one of these fields: Y, X
+
+ // Make sure we don't give Y an initializer.
+ TestEnum Y;
+ // CHECK-FIXES-NOT: TestEnum Y{};
+
+ int X;
+ // CHECK-FIXES: int X{};
+};
+
+struct PositiveAnonymousUnionAndStruct {
+ PositiveAnonymousUnionAndStruct() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B, Y, Z, C, D, E, F, X
+
+ union {
+ int A;
+ // CHECK-FIXES: int A{};
+ short B;
+ };
+
+ struct {
+ int Y;
+ // CHECK-FIXES: int Y{};
+ char *Z;
+ // CHECK-FIXES: char *Z{};
+
+ struct {
+ short C;
+ // CHECK-FIXES: short C{};
+ double D;
+ // CHECK-FIXES: double D{};
+ };
+
+ union {
+ long E;
+ // CHECK-FIXES: long E{};
+ float F;
+ };
+ };
+ int X;
+ // CHECK-FIXES: int X{};
+};
+
+// This check results in a CXXConstructorDecl with no body.
+struct NegativeDeletedConstructor : NegativeAggregateType {
+ NegativeDeletedConstructor() = delete;
+
+ Template<int> F;
+};
+
+// This pathological template fails to compile if actually instantiated. It
+// results in the check seeing a null RecordDecl when examining the base class
+// initializer list.
+template <typename T>
+class PositiveSelfInitialization : NegativeAggregateType
+{
+ PositiveSelfInitialization() : PositiveSelfInitialization() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-FIXES: PositiveSelfInitialization() : NegativeAggregateType(), PositiveSelfInitialization() {}
+};
+
+class PositiveIndirectMember {
+ struct {
+ int *A;
+ // CHECK-FIXES: int *A{};
+ };
+
+ PositiveIndirectMember() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A
+};
+
+void Bug30487()
+{
+ NegativeInClassInitializedDefaulted s;
+}
+
+struct PositiveVirtualMethod {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: F
+ int F;
+ // CHECK-FIXES: int F{};
+ virtual int f() = 0;
+};
+
+struct PositiveVirtualDestructor {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: F
+ PositiveVirtualDestructor() = default;
+ int F;
+ // CHECK-FIXES: int F{};
+ virtual ~PositiveVirtualDestructor() {}
+};
+
+struct PositiveVirtualBase : public virtual NegativeAggregateType {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: constructor does not initialize these fields: F
+ int F;
+ // CHECK-FIXES: int F{};
+};
+
+template <typename T>
+struct PositiveTemplateVirtualDestructor {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: F
+ T Val;
+ int F;
+ // CHECK-FIXES: int F{};
+ virtual ~PositiveTemplateVirtualDestructor() = default;
+};
+
+template struct PositiveTemplateVirtualDestructor<int>;
+
+#define UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(FIELD) \
+ struct UninitializedFieldVirtual##FIELD { \
+ int FIELD; \
+ virtual ~UninitializedFieldVirtual##FIELD() {} \
+ }; \
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int FIELD;
+
+UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(F);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(G);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: G
+
+struct NegativeEmpty {
+};
+
+static void NegativeEmptyVar() {
+ NegativeEmpty e;
+ (void)e;
+}
+
+struct NegativeEmptyMember {
+ NegativeEmptyMember() {}
+ NegativeEmpty e;
+};
+
+struct NegativeEmptyBase : NegativeEmpty {
+ NegativeEmptyBase() {}
+};
+
+struct NegativeEmptyArrayMember {
+ NegativeEmptyArrayMember() {}
+ char e[0];
+};
+
+struct NegativeIncompleteArrayMember {
+ NegativeIncompleteArrayMember() {}
+ char e[];
+};
+
+template <typename T> class NoCrash {
+ class B : public NoCrash {
+ template <typename U> B(U u) {}
+ };
+};
+
+struct PositiveBitfieldMember {
+ PositiveBitfieldMember() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ unsigned F : 5;
+ // CHECK-FIXES-NOT: unsigned F : 5{};
+};
+
+struct NegativeUnnamedBitfieldMember {
+ NegativeUnnamedBitfieldMember() {}
+ unsigned : 5;
+};
+
+struct NegativeInitializedBitfieldMembers {
+ NegativeInitializedBitfieldMembers() : F(3) { G = 2; }
+ unsigned F : 5;
+ unsigned G : 5;
+};
+
+struct NegativeImplicitInheritedCtorBase {
+ NegativeImplicitInheritedCtorBase(unsigned F) : F(F) {}
+ unsigned F;
+};
+
+struct NegativeImplicitInheritedCtor : NegativeImplicitInheritedCtorBase {
+ using NegativeImplicitInheritedCtorBase::NegativeImplicitInheritedCtorBase;
+};
+
+void Bug33557() {
+ NegativeImplicitInheritedCtor I(5);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-reinterpret-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-reinterpret-cast.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-reinterpret-cast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-reinterpret-cast.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,6 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-reinterpret-cast %t
+
+int i = 0;
+void *j;
+void f() { j = reinterpret_cast<void *>(i); }
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-static-cast-downcast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-static-cast-downcast.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-static-cast-downcast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-static-cast-downcast.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,118 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-static-cast-downcast %t
+
+class Base {
+};
+
+class Derived : public Base {
+};
+
+class Base2 {
+};
+
+class MultiDerived : public Base, public Base2 {
+};
+
+class PolymorphicBase {
+public:
+ virtual ~PolymorphicBase();
+};
+
+class PolymorphicDerived : public PolymorphicBase {
+};
+
+class PolymorphicMultiDerived : public Base, public PolymorphicBase {
+};
+
+void pointers() {
+
+ auto P0 = static_cast<Derived*>(new Base());
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+ const Base* B0;
+ auto PC0 = static_cast<const Derived*>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+ auto P1 = static_cast<Base*>(new Derived()); // OK, upcast to a public base
+ auto P2 = static_cast<Base*>(new MultiDerived()); // OK, upcast to a public base
+ auto P3 = static_cast<Base2*>(new MultiDerived()); // OK, upcast to a public base
+}
+
+void pointers_polymorphic() {
+
+ auto PP0 = static_cast<PolymorphicDerived*>(new PolymorphicBase());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto PP0 = dynamic_cast<PolymorphicDerived*>(new PolymorphicBase());
+
+ const PolymorphicBase* B0;
+ auto PPC0 = static_cast<const PolymorphicDerived*>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto PPC0 = dynamic_cast<const PolymorphicDerived*>(B0);
+
+
+ auto B1 = static_cast<PolymorphicBase*>(new PolymorphicDerived()); // OK, upcast to a public base
+ auto B2 = static_cast<PolymorphicBase*>(new PolymorphicMultiDerived()); // OK, upcast to a public base
+ auto B3 = static_cast<Base*>(new PolymorphicMultiDerived()); // OK, upcast to a public base
+}
+
+void arrays() {
+ Base ArrayOfBase[10];
+ auto A0 = static_cast<Derived*>(ArrayOfBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+}
+
+void arrays_polymorphic() {
+ PolymorphicBase ArrayOfPolymorphicBase[10];
+ auto AP0 = static_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto AP0 = dynamic_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
+}
+
+void references() {
+ Base B0;
+ auto R0 = static_cast<Derived&>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+ Base& RefToBase = B0;
+ auto R1 = static_cast<Derived&>(RefToBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+ const Base& ConstRefToBase = B0;
+ auto RC1 = static_cast<const Derived&>(ConstRefToBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+
+ Derived RD1;
+ auto R2 = static_cast<Base&>(RD1); // OK, upcast to a public base
+}
+
+void references_polymorphic() {
+ PolymorphicBase B0;
+ auto RP0 = static_cast<PolymorphicDerived&>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RP0 = dynamic_cast<PolymorphicDerived&>(B0);
+
+ PolymorphicBase& RefToPolymorphicBase = B0;
+ auto RP1 = static_cast<PolymorphicDerived&>(RefToPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto RP1 = dynamic_cast<PolymorphicDerived&>(RefToPolymorphicBase);
+
+ const PolymorphicBase& ConstRefToPolymorphicBase = B0;
+ auto RPC2 = static_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto RPC2 = dynamic_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
+
+ PolymorphicDerived d1;
+ auto RP2 = static_cast<PolymorphicBase&>(d1); // OK, upcast to a public base
+}
+
+template<class B, class D>
+void templ() {
+ auto B0 = static_cast<B*>(new D());
+}
+
+void templ_bad_call() {
+ templ<Derived, Base>(); //FIXME: this should trigger a warning
+}
+
+void templ_good_call() {
+ templ<Base, Derived>(); // OK, upcast to a public base
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-union-access.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-union-access.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-union-access.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-union-access.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-union-access %t
+
+union U {
+ bool union_member1;
+ char union_member2;
+} u;
+
+struct S {
+ int non_union_member;
+ union {
+ bool union_member;
+ };
+ union {
+ char union_member2;
+ } u;
+} s;
+
+
+void f(char);
+void f2(U);
+void f3(U&);
+void f4(U*);
+
+void check()
+{
+ u.union_member1 = true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access]
+ auto b = u.union_member2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not access members of unions; use (boost::)variant instead
+ auto a = &s.union_member;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not access members of unions; use (boost::)variant instead
+ f(s.u.union_member2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not access members of unions; use (boost::)variant instead
+
+ s.non_union_member = 2; // OK
+
+ U u2 = u; // OK
+ f2(u); // OK
+ f3(u); // OK
+ f4(&u); // OK
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,51 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-vararg %t
+
+void f(int i);
+void f_vararg(int i, ...);
+
+struct C {
+ void g_vararg(...);
+ void g(const char*);
+} c;
+
+template<typename... P>
+void cpp_vararg(P... p);
+
+void check() {
+ f_vararg(1, 7, 9);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]
+ c.g_vararg("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not call c-style vararg functions
+
+ f(3); // OK
+ c.g("foo"); // OK
+ cpp_vararg(1, 7, 9); // OK
+}
+
+// ... as a parameter is allowed (e.g. for SFINAE)
+template <typename T>
+void CallFooIfAvailableImpl(T& t, ...) {
+ // nothing
+}
+template <typename T>
+void CallFooIfAvailableImpl(T& t, decltype(t.foo())*) {
+ t.foo();
+}
+template <typename T>
+void CallFooIfAvailable(T& t) {
+ CallFooIfAvailableImpl(t, 0); // OK to call variadic function when the argument is a literal 0
+}
+
+#include <stdarg.h>
+void my_printf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call c-style vararg functions
+ va_list n;
+ va_copy(n, ap); // Don't warn, va_copy is anyway useless without va_start
+ int i = va_arg(ap, int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use va_start/va_arg to define c-style vararg functions; use variadic templates instead
+ va_end(ap); // Don't warn, va_end is anyway useless without va_start
+}
+
+int my_vprintf(const char* format, va_list arg ); // OK to declare function taking va_list
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-slicing.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-slicing.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-slicing.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-slicing.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,100 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-slicing %t
+
+class Base {
+ int i;
+ void f() {}
+ virtual void g() {}
+};
+
+class DerivedWithMemberVariables : public Base {
+ void f();
+ int j;
+};
+
+class TwiceDerivedWithNoMemberVariables : public DerivedWithMemberVariables {
+ void f();
+};
+
+class DerivedWithOverride : public Base {
+ void f();
+ void g() override {}
+};
+
+class TwiceDerivedWithNoOverride : public DerivedWithOverride {
+ void f();
+};
+
+void TakesBaseByValue(Base base);
+
+DerivedWithMemberVariables ReturnsDerived();
+
+void positivesWithMemberVariables() {
+ DerivedWithMemberVariables b;
+ Base a{b};
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state [cppcoreguidelines-slicing]
+ a = b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+ TakesBaseByValue(b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+
+ TwiceDerivedWithNoMemberVariables c;
+ a = c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'TwiceDerivedWithNoMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+
+ a = ReturnsDerived();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+}
+
+void positivesWithOverride() {
+ DerivedWithOverride b;
+ Base a{b};
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+ a = b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+ TakesBaseByValue(b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+
+ TwiceDerivedWithNoOverride c;
+ a = c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+}
+
+void TakesBaseByReference(Base &base);
+
+class DerivedThatAddsVirtualH : public Base {
+ virtual void h();
+};
+
+class DerivedThatOverridesH : public DerivedThatAddsVirtualH {
+ void h() override;
+};
+
+void negatives() {
+ // OK, simple copying from the same type.
+ Base a;
+ TakesBaseByValue(a);
+ DerivedWithMemberVariables b;
+ DerivedWithMemberVariables c{b};
+ b = c;
+
+ // OK, derived type does not have extra state.
+ TwiceDerivedWithNoMemberVariables d;
+ DerivedWithMemberVariables e{d};
+ e = d;
+
+ // OK, derived does not override any method.
+ TwiceDerivedWithNoOverride f;
+ DerivedWithOverride g{f};
+ g = f;
+
+ // OK, no copying.
+ TakesBaseByReference(d);
+ TakesBaseByReference(f);
+
+ // Derived type overrides methods, but these methods are not in the base type,
+ // so cannot be called accidentally. Right now this triggers, but we might
+ // want to allow it.
+ DerivedThatOverridesH h;
+ a = h;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedThatOverridesH' to 'Base' discards override 'h'
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-cxx-03.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-cxx-03.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-cxx-03.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-cxx-03.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy -std=c++98 %s cppcoreguidelines-special-member-functions %t
+
+class DefinesDestructor {
+ ~DefinesDestructor();
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDestructor' defines a non-default destructor but does not define a copy constructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyConstructor {
+ DefinesCopyConstructor(const DefinesCopyConstructor &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyConstructor' defines a copy constructor but does not define a destructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyAssignment {
+ DefinesCopyAssignment &operator=(const DefinesCopyAssignment &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyAssignment' defines a copy assignment operator but does not define a destructor or a copy constructor [cppcoreguidelines-special-member-functions]
+
+class DefinesNothing {
+};
+
+class DefinesEverything {
+ DefinesEverything(const DefinesEverything &);
+ DefinesEverything &operator=(const DefinesEverything &);
+ ~DefinesEverything();
+};
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-relaxed.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-relaxed.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-relaxed.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions-relaxed.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,71 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t -- -config="{CheckOptions: [{key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions, value: 1}, {key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor, value: 1}]}" --
+
+class DefinesDestructor {
+ ~DefinesDestructor();
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDestructor' defines a non-default destructor but does not define a copy constructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesDefaultedDestructor {
+ ~DefinesDefaultedDestructor() = default;
+};
+
+class DefinesCopyConstructor {
+ DefinesCopyConstructor(const DefinesCopyConstructor &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyConstructor' defines a copy constructor but does not define a destructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyAssignment {
+ DefinesCopyAssignment &operator=(const DefinesCopyAssignment &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyAssignment' defines a copy assignment operator but does not define a destructor or a copy constructor [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveConstructor {
+ DefinesMoveConstructor(DefinesMoveConstructor &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor, a copy constructor, a copy assignment operator or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveAssignment {
+ DefinesMoveAssignment &operator=(DefinesMoveAssignment &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor, a copy constructor, a copy assignment operator or a move constructor [cppcoreguidelines-special-member-functions]
+class DefinesNothing {
+};
+
+class DefinesEverything {
+ DefinesEverything(const DefinesEverything &);
+ DefinesEverything &operator=(const DefinesEverything &);
+ DefinesEverything(DefinesEverything &&);
+ DefinesEverything &operator=(DefinesEverything &&);
+ ~DefinesEverything();
+};
+
+class DeletesEverything {
+ DeletesEverything(const DeletesEverything &) = delete;
+ DeletesEverything &operator=(const DeletesEverything &) = delete;
+ DeletesEverything(DeletesEverything &&) = delete;
+ DeletesEverything &operator=(DeletesEverything &&) = delete;
+ ~DeletesEverything() = delete;
+};
+
+class DeletesCopyDefaultsMove {
+ DeletesCopyDefaultsMove(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove &operator=(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove(DeletesCopyDefaultsMove &&) = default;
+ DeletesCopyDefaultsMove &operator=(DeletesCopyDefaultsMove &&) = default;
+ ~DeletesCopyDefaultsMove() = default;
+};
+
+template <typename T>
+struct TemplateClass {
+ TemplateClass() = default;
+ TemplateClass(const TemplateClass &);
+ TemplateClass &operator=(const TemplateClass &);
+ TemplateClass(TemplateClass &&);
+ TemplateClass &operator=(TemplateClass &&);
+ ~TemplateClass();
+};
+
+// Multiple instantiations of a class template will trigger multiple matches for defined special members.
+// This should not cause problems.
+TemplateClass<int> InstantiationWithInt;
+TemplateClass<double> InstantiationWithDouble;
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/cppcoreguidelines-special-member-functions.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,72 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t
+
+class DefinesDestructor {
+ ~DefinesDestructor();
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDestructor' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesDefaultedDestructor {
+ ~DefinesDefaultedDestructor() = default;
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDefaultedDestructor' defines a default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyConstructor {
+ DefinesCopyConstructor(const DefinesCopyConstructor &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyConstructor' defines a copy constructor but does not define a destructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyAssignment {
+ DefinesCopyAssignment &operator=(const DefinesCopyAssignment &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyAssignment' defines a copy assignment operator but does not define a destructor, a copy constructor, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveConstructor {
+ DefinesMoveConstructor(DefinesMoveConstructor &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor, a copy constructor, a copy assignment operator or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveAssignment {
+ DefinesMoveAssignment &operator=(DefinesMoveAssignment &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor, a copy constructor, a copy assignment operator or a move constructor [cppcoreguidelines-special-member-functions]
+class DefinesNothing {
+};
+
+class DefinesEverything {
+ DefinesEverything(const DefinesEverything &);
+ DefinesEverything &operator=(const DefinesEverything &);
+ DefinesEverything(DefinesEverything &&);
+ DefinesEverything &operator=(DefinesEverything &&);
+ ~DefinesEverything();
+};
+
+class DeletesEverything {
+ DeletesEverything(const DeletesEverything &) = delete;
+ DeletesEverything &operator=(const DeletesEverything &) = delete;
+ DeletesEverything(DeletesEverything &&) = delete;
+ DeletesEverything &operator=(DeletesEverything &&) = delete;
+ ~DeletesEverything() = delete;
+};
+
+class DeletesCopyDefaultsMove {
+ DeletesCopyDefaultsMove(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove &operator=(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove(DeletesCopyDefaultsMove &&) = default;
+ DeletesCopyDefaultsMove &operator=(DeletesCopyDefaultsMove &&) = default;
+ ~DeletesCopyDefaultsMove() = default;
+};
+
+template <typename T>
+struct TemplateClass {
+ TemplateClass() = default;
+ TemplateClass(const TemplateClass &);
+ TemplateClass &operator=(const TemplateClass &);
+ TemplateClass(TemplateClass &&);
+ TemplateClass &operator=(TemplateClass &&);
+ ~TemplateClass();
+};
+
+// Multiple instantiations of a class template will trigger multiple matches for defined special members.
+// This should not cause problems.
+TemplateClass<int> InstantiationWithInt;
+TemplateClass<double> InstantiationWithDouble;
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-avoid-spinlock.m
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-avoid-spinlock.m?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-avoid-spinlock.m (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-avoid-spinlock.m Fri Oct 11 05:05:42 2019
@@ -0,0 +1,15 @@
+// RUN: %check_clang_tidy %s darwin-avoid-spinlock %t
+
+typedef int OSSpinLock;
+
+ at implementation Foo
+- (void)f {
+ int i = 1;
+ OSSpinlockLock(&i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use os_unfair_lock_lock() or dispatch queue APIs instead of the deprecated OSSpinLock [darwin-avoid-spinlock]
+ OSSpinlockTry(&i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use os_unfair_lock_lock() or dispatch queue APIs instead of the deprecated OSSpinLock [darwin-avoid-spinlock]
+ OSSpinlockUnlock(&i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use os_unfair_lock_lock() or dispatch queue APIs instead of the deprecated OSSpinLock [darwin-avoid-spinlock]
+}
+ at end
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-dispatch-once-nonstatic.mm
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-dispatch-once-nonstatic.mm?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-dispatch-once-nonstatic.mm (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/darwin-dispatch-once-nonstatic.mm Fri Oct 11 05:05:42 2019
@@ -0,0 +1,48 @@
+// RUN: %check_clang_tidy %s darwin-dispatch-once-nonstatic %t
+
+typedef int dispatch_once_t;
+extern void dispatch_once(dispatch_once_t *pred, void(^block)(void));
+
+
+void bad_dispatch_once(dispatch_once_t once, void(^block)(void)) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: dispatch_once_t variables must have static or global storage duration; function parameters should be pointer references [darwin-dispatch-once-nonstatic]
+
+// file-scope dispatch_once_ts have static storage duration.
+dispatch_once_t global_once;
+static dispatch_once_t file_static_once;
+namespace {
+dispatch_once_t anonymous_once;
+} // end anonymous namespace
+
+int Correct(void) {
+ static int value;
+ static dispatch_once_t once;
+ dispatch_once(&once, ^{
+ value = 1;
+ });
+ return value;
+}
+
+int Incorrect(void) {
+ static int value;
+ dispatch_once_t once;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: dispatch_once_t variables must have static or global storage duration [darwin-dispatch-once-nonstatic]
+ // CHECK-FIXES: static dispatch_once_t once;
+ dispatch_once(&once, ^{
+ value = 1;
+ });
+ return value;
+}
+
+struct OnceStruct {
+ static dispatch_once_t staticOnce; // Allowed
+ int value;
+ dispatch_once_t once; // Allowed (at this time)
+};
+
+ at interface MyObject {
+ dispatch_once_t _once;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: dispatch_once_t variables must have static or global storage duration and cannot be Objective-C instance variables [darwin-dispatch-once-nonstatic]
+ // CHECK-FIXES: dispatch_once_t _once;
+}
+ at end
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-calls.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-calls.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-calls.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-calls.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,36 @@
+// RUN: %check_clang_tidy %s fuchsia-default-arguments-calls %t
+
+int foo(int value = 5) { return value; }
+
+int f() {
+ foo();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls]
+ // CHECK-NOTES: [[@LINE-5]]:9: note: default parameter was declared here
+}
+
+int bar(int value) { return value; }
+
+int n() {
+ foo(0);
+ bar(0);
+}
+
+void x(int i = 12);
+
+struct S {
+ void x(int i);
+};
+
+void S::x(int i = 12) {}
+
+int main() {
+ S s;
+ s.x();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls]
+ // CHECK-NOTES: [[@LINE-6]]:11: note: default parameter was declared here
+ // CHECK-NEXT: void S::x(int i = 12) {}
+ x();
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls]
+ // CHECK-NOTES: [[@LINE-16]]:8: note: default parameter was declared here
+ // CHECK-NEXT: void x(int i = 12);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-declarations.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-declarations.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-declarations.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-default-arguments-declarations.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s fuchsia-default-arguments-declarations %t
+
+int foo(int value = 5) { return value; }
+// CHECK-NOTES: [[@LINE-1]]:9: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments-declarations]
+// CHECK-FIXES: int foo(int value) { return value; }
+
+int bar(int value) { return value; }
+
+class Baz {
+public:
+ int a(int value = 5) { return value; }
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments-declarations]
+ // CHECK-FIXES: int a(int value) { return value; }
+
+ int b(int value) { return value; }
+};
+
+class Foo {
+ // Fix should be suggested in declaration
+ int a(int value = 53);
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments-declarations]
+ // CHECK-FIXES: int a(int value);
+};
+
+// Fix shouldn't be suggested in implementation
+int Foo::a(int value) {
+ return value;
+}
+
+// Elided functions
+void f(int = 5) {};
+// CHECK-NOTES: [[@LINE-1]]:8: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments-declarations]
+// CHECK-FIXES: void f(int) {};
+
+void g(int) {};
+
+// Should not suggest fix for macro-defined parameters
+#define D(val) = val
+
+void h(int i D(5));
+// CHECK-NOTES: [[@LINE-1]]:8: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments-declarations]
+// CHECK-FIXES-NOT: void h(int i);
+
+void x(int i);
+void x(int i = 12);
+// CHECK-NOTES: [[@LINE-1]]:8: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments-declarations]
+// CHECK-FIXES: void x(int i);
+
+void x(int i) {}
+
+struct S {
+ void x(int i);
+};
+
+void S::x(int i = 12) {}
+// CHECK-NOTES: [[@LINE-1]]:11: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments-declarations]
+// CHECK-FIXES: void S::x(int i) {}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-multiple-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-multiple-inheritance.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-multiple-inheritance.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-multiple-inheritance.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,150 @@
+// RUN: %check_clang_tidy %s fuchsia-multiple-inheritance %t
+
+class Base_A {
+public:
+ virtual int foo() { return 0; }
+};
+
+class Base_B {
+public:
+ virtual int bar() { return 0; }
+};
+
+class Base_A_child : public Base_A {
+public:
+ virtual int baz() { return 0; }
+};
+
+class Interface_A {
+public:
+ virtual int foo() = 0;
+};
+
+class Interface_B {
+public:
+ virtual int bar() = 0;
+};
+
+class Interface_C {
+public:
+ virtual int blat() = 0;
+};
+
+class Interface_A_with_member {
+public:
+ virtual int foo() = 0;
+ int val = 0;
+};
+
+class Interface_with_A_Parent : public Base_A {
+public:
+ virtual int baz() = 0;
+};
+
+// Shouldn't warn on forward declarations.
+class Bad_Child1;
+
+// Inherits from multiple concrete classes.
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: class Bad_Child1 : public Base_A, Base_B {};
+class Bad_Child1 : public Base_A, Base_B {};
+
+// CHECK-MESSAGES: [[@LINE+1]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+class Bad_Child2 : public Base_A, Interface_A_with_member {
+ virtual int foo() override { return 0; }
+};
+
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: class Bad_Child3 : public Interface_with_A_Parent, Base_B {
+class Bad_Child3 : public Interface_with_A_Parent, Base_B {
+ virtual int baz() override { return 0; }
+};
+
+// Easy cases of single inheritance
+class Simple_Child1 : public Base_A {};
+class Simple_Child2 : public Interface_A {
+ virtual int foo() override { return 0; }
+};
+
+// Valid uses of multiple inheritance
+class Good_Child1 : public Interface_A, Interface_B {
+ virtual int foo() override { return 0; }
+ virtual int bar() override { return 0; }
+};
+
+class Good_Child2 : public Base_A, Interface_B {
+ virtual int bar() override { return 0; }
+};
+
+class Good_Child3 : public Base_A_child, Interface_C, Interface_B {
+ virtual int bar() override { return 0; }
+ virtual int blat() override { return 0; }
+};
+
+struct B1 { int x; };
+struct B2 { int x;};
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D : B1, B2 {};
+struct D1 : B1, B2 {};
+
+struct Base1 { virtual void foo() = 0; };
+struct V1 : virtual Base1 {};
+struct V2 : virtual Base1 {};
+struct D2 : V1, V2 {};
+
+struct Base2 { virtual void foo(); };
+struct V3 : virtual Base2 {};
+struct V4 : virtual Base2 {};
+struct D3 : V3, V4 {};
+
+struct Base3 {};
+struct V5 : virtual Base3 { virtual void f(); };
+struct V6 : virtual Base3 { virtual void g(); };
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D4 : V5, V6 {};
+struct D4 : V5, V6 {};
+
+struct Base4 {};
+struct V7 : virtual Base4 { virtual void f() = 0; };
+struct V8 : virtual Base4 { virtual void g() = 0; };
+struct D5 : V7, V8 {};
+
+struct Base5 { virtual void f() = 0; };
+struct V9 : virtual Base5 { virtual void f(); };
+struct V10 : virtual Base5 { virtual void g() = 0; };
+struct D6 : V9, V10 {};
+
+struct Base6 { virtual void f(); };
+struct Base7 { virtual void g(); };
+struct V15 : virtual Base6 { virtual void f() = 0; };
+struct V16 : virtual Base7 { virtual void g() = 0; };
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D9 : V15, V16 {};
+struct D9 : V15, V16 {};
+
+struct Static_Base { static void foo(); };
+struct V11 : virtual Static_Base {};
+struct V12 : virtual Static_Base {};
+struct D7 : V11, V12 {};
+
+struct Static_Base_2 {};
+struct V13 : virtual Static_Base_2 { static void f(); };
+struct V14 : virtual Static_Base_2 { static void g(); };
+struct D8 : V13, V14 {};
+
+template<typename T> struct A : T {};
+template<typename T> struct B : virtual T {};
+
+template<typename> struct C {};
+template<typename T> struct D : C<T> {};
+
+// Check clang_tidy does not crash on this code.
+template <class T>
+struct WithTemplBase : T {
+ WithTemplBase();
+};
+
+int test_no_crash() {
+ auto foo = []() {};
+ WithTemplBase<decltype(foo)>();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-overloaded-operator.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-overloaded-operator.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-overloaded-operator.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy %s fuchsia-overloaded-operator %t
+
+class A {
+public:
+ int operator+(int);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: overloading 'operator+' is disallowed
+};
+
+class B {
+public:
+ B &operator=(const B &Other);
+ // CHECK-MESSAGES-NOT: [[@LINE-1]]:3: warning: overloading 'operator=' is disallowed
+ B &operator=(B &&Other);
+ // CHECK-MESSAGES-NOT: [[@LINE-1]]:3: warning: overloading 'operator=' is disallowed
+};
+
+A operator-(const A &A1, const A &A2);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: overloading 'operator-' is disallowed
+
+void operator delete(void*, void*) throw();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: overloading 'operator delete' is disallowed
+
+auto x = []{};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-all.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-all.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-all.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-all.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: ''}]}" \
+// RUN: -- -I %S/Inputs/fuchsia-restrict-system-includes -isystem %S/Inputs/fuchsia-restrict-system-includes/system
+
+#include <cstdlib.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include cstdlib.h not allowed
+#include <cstdarg.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include cstdarg.h not allowed
+#include <t.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-glob.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-glob.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-glob.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-glob.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: 'cstd*'}]}" \
+// RUN: -- -I %S/Inputs/fuchsia-restrict-system-includes -isystem %S/Inputs/fuchsia-restrict-system-includes/system
+
+#include <cstdlib.h>
+#include <cstdarg.h>
+#include <t.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
+// CHECK-FIXES-NOT: #include <t.h>
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-headers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-headers.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-headers.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes-headers.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,24 @@
+// RUN: rm -rf %T/Headers
+// RUN: mkdir %T/Headers
+// RUN: cp -r %S/Inputs/fuchsia-restrict-system-includes %T/Headers/fuchsia-restrict-system-includes
+// RUN: %check_clang_tidy -std=c++11 %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: 'transitive.h,s.h'}]}" \
+// RUN: -system-headers -header-filter=.* \
+// RUN: -- -I %T/Headers/fuchsia-restrict-system-includes -isystem %T/Headers/fuchsia-restrict-system-includes/system
+// RUN: FileCheck -input-file=%T/Headers/fuchsia-restrict-system-includes/transitive2.h %s -check-prefix=CHECK-FIXES
+// RUN: rm -rf %T/Headers
+// FIXME: Make the test work in all language modes.
+
+// transitive.h includes <r.h> and <t.h>
+#include <transitive.h>
+// CHECK-MESSAGES: :1:1: warning: system include r.h not allowed, transitively included from {{.*}}
+// CHECK-MESSAGES: :2:1: warning: system include t.h not allowed, transitively included from {{.*}}
+
+// transitive.h includes <s.h> and <t.h>
+#include "transitive2.h"
+// CHECK-MESSAGES: :2:1: warning: system include t.h not allowed, transitively included from {{.*}}
+// CHECK-FIXES-NOT: #include <t.h>
+
+int main() {
+ // f() is declared in r.h
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-restrict-system-includes.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: 's.h'}]}" \
+// RUN: -- -I %S/Inputs/fuchsia-restrict-system-includes -isystem %S/Inputs/fuchsia-restrict-system-includes/system
+
+#include "a.h"
+
+#include <s.h>
+#include <t.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
+// CHECK-FIXES-NOT: #include <t.h>
+
+#include "s.h"
+#include "t.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
+// CHECK-FIXES-NOT: #include "t.h"
+
+#define foo <j.h>
+
+#include foo
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include j.h not allowed
+// CHECK-FIXES-NOT: #include foo
+
+#/* comment */ include /* comment */ foo
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include j.h not allowed
+// CHECK-FIXES-NOT: # /* comment */ include /* comment */ foo
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-statically-constructed-objects.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-statically-constructed-objects.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-statically-constructed-objects.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-statically-constructed-objects.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,91 @@
+// RUN: %check_clang_tidy %s fuchsia-statically-constructed-objects %t
+
+// Trivial static is fine
+static int i;
+
+class ClassWithNoCtor {};
+
+class ClassWithCtor {
+public:
+ ClassWithCtor(int Val) : Val(Val) {}
+private:
+ int Val;
+};
+
+class ClassWithConstexpr {
+public:
+ ClassWithConstexpr(int Val1, int Val2) : Val(Val1) {}
+ constexpr ClassWithConstexpr(int Val) : Val(Val) {}
+
+private:
+ int Val;
+};
+
+ClassWithNoCtor A;
+ClassWithConstexpr C(0);
+ClassWithConstexpr E(0, 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: ClassWithConstexpr E(0, 1);
+ClassWithCtor G(0);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: ClassWithCtor G(0);
+
+static ClassWithNoCtor A2;
+static ClassWithConstexpr C2(0);
+static ClassWithConstexpr E2(0, 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static ClassWithConstexpr E2(0, 1);
+static ClassWithCtor G2(0);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static ClassWithCtor G2(0);
+
+struct StructWithConstexpr { constexpr StructWithConstexpr(int Val) {} };
+struct StructWithNoCtor {};
+struct StructWithCtor { StructWithCtor(); };
+
+StructWithNoCtor SNoCtor;
+StructWithConstexpr SConstexpr(0);
+StructWithCtor SCtor;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: StructWithCtor SCtor;
+
+static StructWithConstexpr SConstexpr2(0);
+static StructWithNoCtor SNoCtor2;
+static StructWithCtor SCtor2;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static StructWithCtor SCtor2;
+
+extern StructWithCtor SCtor3;
+
+class ClassWithStaticMember {
+private:
+ static StructWithNoCtor S;
+};
+
+ClassWithStaticMember Z();
+
+class S {
+ int Val;
+public:
+ constexpr S(int i) : Val(100 / i) {}
+ int getVal() const { return Val; }
+};
+
+static S s1(1);
+static S s2(0);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static S s2(0);
+
+extern int get_i();
+static S s3(get_i());
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static S s3(get_i());
+
+void f() {
+ // Locally static is fine
+ static int i;
+ static ClassWithNoCtor A2;
+ static ClassWithConstexpr C2(0);
+ static ClassWithConstexpr E2(0, 1);
+ static ClassWithCtor G2(0);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-trailing-return.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-trailing-return.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-trailing-return.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-trailing-return.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy %s fuchsia-trailing-return %t
+
+int add_one(const int arg) { return arg; }
+
+auto get_add_one() -> int (*)(const int) {
+ // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is disallowed for this type of declaration
+ // CHECK-NEXT: auto get_add_one() -> int (*)(const int) {
+ return add_one;
+}
+
+auto lambda = [](double x, double y) {return x + y;};
+
+auto lambda2 = [](double x, double y) -> double {return x + y;};
+
+int main() {
+ get_add_one()(5);
+ return 0;
+}
+
+template <typename T1, typename T2>
+auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
+ return lhs + rhs;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-virtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-virtual-inheritance.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-virtual-inheritance.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/fuchsia-virtual-inheritance.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s fuchsia-virtual-inheritance %t
+
+class A {
+public:
+ A(int value) : val(value) {}
+
+ int do_A() { return val; }
+
+private:
+ int val;
+};
+
+class B : public virtual A {
+ // CHECK-MESSAGES: [[@LINE-1]]:1: warning: direct virtual inheritance is disallowed [fuchsia-virtual-inheritance]
+ // CHECK-NEXT: class B : public virtual A {
+public:
+ B() : A(0) {}
+ int do_B() { return 1 + do_A(); }
+};
+
+class C : public virtual A {
+ // CHECK-MESSAGES: [[@LINE-1]]:1: warning: direct virtual inheritance is disallowed [fuchsia-virtual-inheritance]
+ // CHECK-NEXT: class C : public virtual A {
+public:
+ C() : A(0) {}
+ int do_C() { return 2 + do_A(); }
+};
+
+class D : public B, public C {
+public:
+ D(int value) : A(value), B(), C() {}
+
+ int do_D() { return do_A() + do_B() + do_C(); }
+};
+
+int main() {
+ A *a = new A(0);
+ B *b = new B();
+ C *c = new C();
+ D *d = new D(0);
+ return 0;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-build-explicit-make-pair.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-build-explicit-make-pair.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-build-explicit-make-pair.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-build-explicit-make-pair.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,51 @@
+// RUN: %check_clang_tidy %s google-build-explicit-make-pair %t
+
+namespace std {
+template <class T1, class T2>
+struct pair {
+ pair(T1 x, T2 y) {}
+};
+
+template <class T1, class T2>
+pair<T1, T2> make_pair(T1 x, T2 y) {
+ return pair<T1, T2>(x, y);
+}
+}
+
+template <typename T>
+void templ(T a, T b) {
+ std::make_pair<T, unsigned>(a, b);
+ std::make_pair<int, int>(1, 2);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, omit template arguments from make_pair
+// CHECK-FIXES: std::make_pair(1, 2)
+}
+
+template <typename T>
+int t();
+
+void test(int i) {
+ std::make_pair<int, int>(i, i);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, omit template arguments from make_pair
+// CHECK-FIXES: std::make_pair(i, i)
+
+ std::make_pair<unsigned, int>(i, i);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, use pair directly
+// CHECK-FIXES: std::pair<unsigned, int>(i, i)
+
+ std::make_pair<int, unsigned>(i, i);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, use pair directly
+// CHECK-FIXES: std::pair<int, unsigned>(i, i)
+
+#define M std::make_pair<int, unsigned>(i, i);
+M
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: for C++11-compatibility, use pair directly
+// Can't fix in macros.
+// CHECK-FIXES: #define M std::make_pair<int, unsigned>(i, i);
+// CHECK-FIXES-NEXT: M
+
+ templ(i, i);
+ templ(1U, 2U);
+
+ std::make_pair(i, 1); // no-warning
+ std::make_pair(t<int>, 1);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-default-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-default-arguments.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-default-arguments.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-default-arguments.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,29 @@
+// RUN: %check_clang_tidy %s google-default-arguments %t
+
+struct A {
+ virtual void f(int I, int J = 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: default arguments on virtual or override methods are prohibited [google-default-arguments]
+};
+
+struct B : public A {
+ void f(int I, int J = 5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: default arguments on virtual or override methods are prohibited
+};
+
+struct C : public B {
+ void f(int I, int J = 5) override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: default arguments on virtual or override methods are prohibited
+};
+
+// Negatives.
+struct D : public B {
+ void f(int I, int J) override;
+};
+
+struct X {
+ void f(int I, int J = 3);
+};
+
+struct Y : public X {
+ void f(int I, int J = 5);
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-explicit-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-explicit-constructor.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-explicit-constructor.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-explicit-constructor.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,188 @@
+// RUN: %check_clang_tidy %s google-explicit-constructor %t
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+struct A {
+ A() {}
+ A(int x, int y) {}
+
+ explicit A(void *x) {}
+ explicit A(void *x, void *y) {}
+ explicit operator bool() const { return true; }
+
+ operator double() const = delete;
+
+ explicit A(const A& a) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: copy constructor should not be declared explicit [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}A(const A& a) {}
+
+ A(int x1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit A(int x1);
+
+ A(double x2, double y = 3.14) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructors that are callable with a single argument must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit A(double x2, double y = 3.14) {}
+
+ template <typename... T>
+ A(T&&... args);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructors that are callable with a single argument
+ // CHECK-FIXES: {{^ }}explicit A(T&&... args);
+};
+
+inline A::A(int x1) {}
+
+struct B {
+ B(std::initializer_list<int> list1) {}
+ B(const std::initializer_list<unsigned> &list2) {}
+ B(std::initializer_list<unsigned> &&list3) {}
+
+ operator bool() const { return true; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator bool' must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit operator bool() const { return true; }
+
+ operator double() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator double' must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit operator double() const;
+
+ explicit B(::std::initializer_list<double> list4) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor should not be declared explicit [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}B(::std::initializer_list<double> list4) {}
+
+ explicit B(const ::std::initializer_list<char> &list5) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
+ // CHECK-FIXES: {{^ }}B(const ::std::initializer_list<char> &list5) {}
+
+ explicit B(::std::initializer_list<char> &&list6) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
+ // CHECK-FIXES: {{^ }}B(::std::initializer_list<char> &&list6) {}
+};
+
+inline B::operator double() const { return 0.0; }
+
+struct StructWithFnPointer {
+ void (*f)();
+} struct_with_fn_pointer = {[] {}};
+
+using namespace std;
+
+struct C {
+ C(initializer_list<int> list1) {}
+ C(const initializer_list<unsigned> &list2) {}
+ C(initializer_list<unsigned> &&list3) {}
+};
+
+template <typename T>
+struct C2 {
+ C2(initializer_list<int> list1) {}
+ C2(const initializer_list<unsigned> &list2) {}
+ C2(initializer_list<unsigned> &&list3) {}
+
+ explicit C2(initializer_list<double> list4) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
+ // CHECK-FIXES: {{^ }}C2(initializer_list<double> list4) {}
+};
+
+template <typename T>
+struct C3 {
+ C3(initializer_list<T> list1) {}
+ C3(const std::initializer_list<T*> &list2) {}
+ C3(::std::initializer_list<T**> &&list3) {}
+
+ template <typename U>
+ C3(initializer_list<U> list3) {}
+};
+
+struct D {
+ template <typename T>
+ explicit D(T t) {}
+};
+
+template <typename T>
+struct E {
+ E(T *pt) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors
+ // CHECK-FIXES: {{^ }}explicit E(T *pt) {}
+ template <typename U>
+ E(U *pu) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors
+ // CHECK-FIXES: {{^ }}explicit E(U *pu) {}
+
+ explicit E(T t) {}
+ template <typename U>
+ explicit E(U u) {}
+};
+
+void f(std::initializer_list<int> list) {
+ D d(list);
+ E<decltype(list)> e(list);
+ E<int> e2(list);
+}
+
+template <typename T>
+struct F {};
+
+template<typename T>
+struct G {
+ operator bool() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator bool' must be marked
+ // CHECK-FIXES: {{^}} explicit operator bool() const;
+ operator F<T>() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator F<type-parameter-0-0>' must be marked
+ // CHECK-FIXES: {{^}} explicit operator F<T>() const;
+ template<typename U>
+ operator F<U>*() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator F<type-parameter-1-0> *' must be marked
+ // CHECK-FIXES: {{^}} explicit operator F<U>*() const;
+};
+
+void f2() {
+ G<int> a;
+ (void)(F<int>)a;
+ if (a) {}
+ (void)(F<int>*)a;
+ (void)(F<int*>*)a;
+
+ G<double> b;
+ (void)(F<double>)b;
+ if (b) {}
+ (void)(F<double>*)b;
+ (void)(F<double*>*)b;
+}
+
+#define DEFINE_STRUCT_WITH_OPERATOR_BOOL(name) \
+ struct name { \
+ operator bool() const; \
+ }
+
+DEFINE_STRUCT_WITH_OPERATOR_BOOL(H);
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-module.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-module.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-module.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-module.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,10 @@
+// RUN: clang-tidy -checks='-*,google*' -config='{}' -dump-config - -- | FileCheck %s
+// CHECK: CheckOptions:
+// CHECK: {{- key: *google-readability-braces-around-statements.ShortStatementLines}}
+// CHECK-NEXT: {{value: *'1'}}
+// CHECK: {{- key: *google-readability-function-size.StatementThreshold}}
+// CHECK-NEXT: {{value: *'800'}}
+// CHECK: {{- key: *google-readability-namespace-comments.ShortNamespaceLines}}
+// CHECK-NEXT: {{value: *'10'}}
+// CHECK: {{- key: *google-readability-namespace-comments.SpacesBeforeComments}}
+// CHECK-NEXT: {{value: *'2'}}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-namespaces.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-namespaces.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-namespaces.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-namespaces.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,52 @@
+// RUN: clang-tidy %s -checks='-*,google-build-namespaces,google-build-using-namespace' -header-filter='.*' -- | FileCheck %s -implicit-check-not="{{warning|error}}:"
+#include "Inputs/google-namespaces.h"
+// CHECK: warning: do not use unnamed namespaces in header files [google-build-namespaces]
+
+using namespace spaaaace;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+using spaaaace::core; // no-warning
+
+namespace std {
+inline namespace literals {
+inline namespace chrono_literals {
+}
+inline namespace complex_literals {
+}
+inline namespace string_literals {
+}
+}
+}
+
+using namespace std::chrono_literals; // no-warning
+using namespace std::complex_literals; // no-warning
+using namespace std::literals; // no-warning
+using namespace std::literals::chrono_literals; // no-warning
+using namespace std::literals::complex_literals; // no-warning
+using namespace std::literals::string_literals; // no-warning
+using namespace std::string_literals; // no-warning
+
+namespace literals {}
+
+using namespace literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+namespace foo {
+inline namespace literals {
+inline namespace bar_literals {}
+}
+}
+
+using namespace foo::literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+using namespace foo::bar_literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+using namespace foo::literals::bar_literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+namespace foo_literals {}
+
+using namespace foo_literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-nsobject-new.m
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-nsobject-new.m?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-nsobject-new.m (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-nsobject-new.m Fri Oct 11 05:05:42 2019
@@ -0,0 +1,80 @@
+// RUN: %check_clang_tidy %s google-objc-avoid-nsobject-new %t
+
+ at interface NSObject
++ (instancetype)new;
++ (instancetype)alloc;
+- (instancetype)init;
+ at end
+
+ at interface NSProxy // Root class with no -init method.
+ at end
+
+// NSDate provides a specific factory method.
+ at interface NSDate : NSObject
++ (instancetype)date;
+ at end
+
+// For testing behavior with Objective-C Generics.
+ at interface NSMutableDictionary<__covariant KeyType, __covariant ObjectType> : NSObject
+ at end
+
+ at class NSString;
+
+#define ALLOCATE_OBJECT(_Type) [_Type new]
+
+void CheckSpecificInitRecommendations(void) {
+ NSObject *object = [NSObject new];
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: do not create objects with +new [google-objc-avoid-nsobject-new]
+ // CHECK-FIXES: [NSObject alloc] init];
+
+ NSDate *correctDate = [NSDate date];
+ NSDate *incorrectDate = [NSDate new];
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: do not create objects with +new [google-objc-avoid-nsobject-new]
+ // CHECK-FIXES: [NSDate date];
+
+ NSObject *macroCreated = ALLOCATE_OBJECT(NSObject); // Shouldn't warn on macros.
+
+ NSMutableDictionary *dict = [NSMutableDictionary<NSString *, NSString *> new];
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: do not create objects with +new [google-objc-avoid-nsobject-new]
+ // CHECK-FIXES: [NSMutableDictionary<NSString *, NSString *> alloc] init];
+}
+
+ at interface Foo : NSObject
++ (instancetype)new; // Declare again to suppress warning.
+- (instancetype)initWithInt:(int)anInt;
+- (instancetype)init __attribute__((unavailable));
+
+- (id)new;
+ at end
+
+ at interface Baz : Foo // Check unavailable -init through inheritance.
+ at end
+
+ at interface ProxyFoo : NSProxy
++ (instancetype)new;
+ at end
+
+void CallNewWhenInitUnavailable(void) {
+ Foo *foo = [Foo new];
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: do not create objects with +new [google-objc-avoid-nsobject-new]
+
+ Baz *baz = [Baz new];
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: do not create objects with +new [google-objc-avoid-nsobject-new]
+
+ // Instance method -new calls may be weird, but are not strictly forbidden.
+ Foo *bar = [[Foo alloc] initWithInt:4];
+ [bar new];
+
+ ProxyFoo *proxy = [ProxyFoo new];
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: do not create objects with +new [google-objc-avoid-nsobject-new]
+}
+
+ at interface HasNewOverride : NSObject
+ at end
+
+ at implementation HasNewOverride
++ (instancetype)new {
+ return [[self alloc] init];
+}
+// CHECK-MESSAGES: [[@LINE-3]]:1: warning: classes should not override +new [google-objc-avoid-nsobject-new]
+ at end
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-throwing-exception.m
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-throwing-exception.m?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-throwing-exception.m (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-avoid-throwing-exception.m Fri Oct 11 05:05:42 2019
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy %s google-objc-avoid-throwing-exception %t
+ at class NSString;
+
+ at interface NSException
+
++ (void)raise:(NSString *)name format:(NSString *)format;
++ (void)raise:(NSString *)name format:(NSString *)format arguments:(NSString *)args; // using NSString type since va_list cannot be recognized here
+
+ at end
+
+ at interface NotException
+
++ (void)raise:(NSString *)name format:(NSString *)format;
+
+ at end
+
+ at implementation Foo
+- (void)f {
+ NSString *foo = @"foo";
+ @throw foo;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception]
+}
+
+- (void)f2 {
+ [NSException raise:@"TestException" format:@"Test"];
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception]
+ [NSException raise:@"TestException" format:@"Test %@" arguments:@"bar"];
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception]
+ [NotException raise:@"NotException" format:@"Test"];
+}
+ at end
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.m
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.m?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.m (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.m Fri Oct 11 05:05:42 2019
@@ -0,0 +1,71 @@
+// RUN: %check_clang_tidy %s google-objc-function-naming %t -- -- -isystem %S/Inputs/Headers
+
+#include <stdio.h>
+
+static void TestImplicitFunctionDeclaration(int a) {
+ // Call a builtin function so that the compiler generates an implicit
+ // function declaration.
+ printf("%d", a);
+}
+
+typedef _Bool bool;
+
+static bool ispositive(int a) { return a > 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: static function named 'ispositive'
+// must be in Pascal case as required by Google Objective-C style guide
+// CHECK-FIXES: static bool Ispositive(int a) { return a > 0; }
+
+static bool is_positive(int a) { return a > 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: static function named 'is_positive'
+// must be in Pascal case as required by Google Objective-C style guide
+// CHECK-FIXES: static bool IsPositive(int a) { return a > 0; }
+
+static bool isPositive(int a) { return a > 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: static function named 'isPositive'
+// must be in Pascal case as required by Google Objective-C style guide
+// CHECK-FIXES: static bool IsPositive(int a) { return a > 0; }
+
+static bool Is_Positive(int a) { return a > 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: static function named 'Is_Positive'
+// must be in Pascal case as required by Google Objective-C style guide
+// CHECK-FIXES: static bool IsPositive(int a) { return a > 0; }
+
+static bool IsPositive(int a) { return a > 0; }
+
+bool ispalindrome(const char *str);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function in global namespace named
+// 'ispalindrome' must have an appropriate prefix followed by Pascal case as
+// required by Google Objective-C style guide
+
+static const char *md5(const char *str) { return 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: static function named 'md5' must be
+// in Pascal case as required by Google Objective-C style guide
+// CHECK-FIXES: static const char *Md5(const char *str) { return 0; }
+
+static const char *MD5(const char *str) { return 0; }
+
+static const char *URL(void) { return "https://clang.llvm.org/"; }
+
+static const char *DEFURL(void) { return "https://clang.llvm.org/"; }
+
+static const char *DEFFooURL(void) { return "https://clang.llvm.org/"; }
+
+static const char *StringFromNSString(id str) { return ""; }
+
+void ABLog_String(const char *str);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function in global namespace named
+// 'ABLog_String' must have an appropriate prefix followed by Pascal case as
+// required by Google Objective-C style guide
+
+void ABLogString(const char *str);
+
+bool IsPrime(int a);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function in global namespace named
+// 'IsPrime' must have an appropriate prefix followed by Pascal case as required
+// by Google Objective-C style guide
+
+const char *ABURL(void) { return "https://clang.llvm.org/"; }
+
+const char *ABFooURL(void) { return "https://clang.llvm.org/"; }
+
+int main(int argc, const char **argv) { return 0; }
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.mm
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.mm?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.mm (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-function-naming.mm Fri Oct 11 05:05:42 2019
@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s google-objc-function-naming %t
+
+void printSomething() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function in global namespace named
+// 'printSomething' must have an appropriate prefix followed by Pascal case as
+// required by Google Objective-C style guide
+
+void PrintSomething() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function in global namespace named
+// 'PrintSomething' must have an appropriate prefix followed by Pascal case as
+// required by Google Objective-C style guide
+
+void ABCBad_Name() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function in global namespace named
+// 'ABCBad_Name' must have an appropriate prefix followed by Pascal case as
+// required by Google Objective-C style guide
+
+namespace {
+
+int foo() { return 0; }
+
+}
+
+namespace bar {
+
+int convert() { return 0; }
+
+}
+
+class Baz {
+public:
+ int value() { return 0; }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.m
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.m?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.m (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.m Fri Oct 11 05:05:42 2019
@@ -0,0 +1,66 @@
+// RUN: %check_clang_tidy %s google-objc-global-variable-declaration %t
+
+ at class NSString;
+
+static NSString* const myConstString = @"hello";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'myConstString' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const kMyConstString = @"hello";
+
+extern NSString* const GlobalConstant = @"hey";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'GlobalConstant' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+
+static NSString* MyString = @"hi";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'MyString' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* gMyString = @"hi";
+
+NSString* globalString = @"test";
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: non-const global variable 'globalString' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: NSString* gGlobalString = @"test";
+
+static NSString* a = @"too simple";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'a' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* a = @"too simple";
+
+static NSString* noDef;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'noDef' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* gNoDef;
+
+static NSString* const _notAlpha = @"NotBeginWithAlpha";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable '_notAlpha' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const _notAlpha = @"NotBeginWithAlpha";
+
+static NSString* const notCap = @"NotBeginWithCap";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'notCap' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const kNotCap = @"NotBeginWithCap";
+
+static NSString* const k_Alpha = @"SecondNotAlpha";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'k_Alpha' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const k_Alpha = @"SecondNotAlpha";
+
+static NSString* const SecondNotCap = @"SecondNotCapOrNumber";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'SecondNotCap' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const kSecondNotCap = @"SecondNotCapOrNumber";
+
+extern NSString* Y2Bad;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'Y2Bad' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: extern NSString* gY2Bad;
+
+static NSString* const kGood = @"hello";
+static NSString* const XYGood = @"hello";
+static NSString* const X1Good = @"hello";
+static NSString* gMyIntGood = 0;
+
+extern NSString* const GTLServiceErrorDomain;
+
+enum GTLServiceError {
+ GTLServiceErrorQueryResultMissing = -3000,
+ GTLServiceErrorWaitTimedOut = -3001,
+};
+
+ at implementation Foo
+- (void)f {
+ int x = 0;
+ static int bar;
+ static const int baz = 42;
+}
+ at end
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.mm
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.mm?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.mm (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-objc-global-variable-declaration.mm Fri Oct 11 05:05:42 2019
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s google-objc-global-variable-declaration %t
+
+ at class NSString;
+static NSString* const myConstString = @"hello";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'myConstString' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const kMyConstString = @"hello";
+
+class MyTest {
+ static int not_objc_style;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-overloaded-unary-and.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-overloaded-unary-and.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-overloaded-unary-and.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-overloaded-unary-and.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s google-runtime-operator %t
+
+struct Foo {
+ void *operator&();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not overload unary operator&, it is dangerous. [google-runtime-operator]
+};
+
+template <typename T>
+struct TFoo {
+ T *operator&();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not overload unary operator&
+};
+
+TFoo<int> tfoo;
+
+struct Bar;
+void *operator&(Bar &b);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not overload unary operator&
+
+// No warnings on binary operators.
+struct Qux {
+ void *operator&(Qux &q);
+};
+
+void *operator&(Qux &q, Qux &r);
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s google-readability-casting %t -- -- -x c
+// The testing script always adds .cpp extension to the input file name, so we
+// need to run clang-tidy directly in order to verify handling of .c files:
+// RUN: clang-tidy --checks=-*,google-readability-casting %s -- -x c++ | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not='{{warning|error}}:'
+// RUN: cp %s %t.main_file.cpp
+// RUN: clang-tidy --checks=-*,google-readability-casting -header-filter='.*' %t.main_file.cpp -- -I%S -DTEST_INCLUDE -x c++ | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not='{{warning|error}}:'
+
+#ifdef TEST_INCLUDE
+
+#undef TEST_INCLUDE
+#include "google-readability-casting.c"
+
+#else
+
+void f(const char *cpc) {
+ const char *cpc2 = (const char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant cast to the same type [google-readability-casting]
+ // CHECK-FIXES: const char *cpc2 = cpc;
+ char *pc = (char*)cpc;
+ typedef const char *Typedef1;
+ (Typedef1)cpc;
+}
+
+#endif
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,324 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s google-readability-casting %t
+// FIXME: Fix the checker to work in C++17 mode.
+
+bool g() { return false; }
+
+enum Enum { Enum1 };
+struct X {};
+struct Y : public X {};
+
+void f(int a, double b, const char *cpc, const void *cpv, X *pX) {
+ const char *cpc2 = (const char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant cast to the same type [google-readability-casting]
+ // CHECK-FIXES: const char *cpc2 = cpc;
+
+ typedef const char *Typedef1;
+ typedef const char *Typedef2;
+ Typedef1 t1;
+ (Typedef2)t1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C-style casts are discouraged; use static_cast (if needed, the cast may be redundant) [google-readability-casting]
+ // CHECK-FIXES: {{^}} static_cast<Typedef2>(t1);
+ (const char*)t1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<const char*>(t1);
+ (Typedef1)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<Typedef1>(cpc);
+ (Typedef1)t1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} t1;
+
+ char *pc = (char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use const_cast [google-readability-casting]
+ // CHECK-FIXES: char *pc = const_cast<char*>(cpc);
+ typedef char Char;
+ Char *pChar = (Char*)pc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} Char *pChar = static_cast<Char*>(pc);
+
+ (Char)*cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<Char>(*cpc);
+
+ (char)*pChar;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<char>(*pChar);
+
+ (const char*)cpv;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: static_cast<const char*>(cpv);
+
+ char *pc2 = (char*)(cpc + 33);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char *pc2 = const_cast<char*>(cpc + 33);
+
+ const char &crc = *cpc;
+ char &rc = (char&)crc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char &rc = const_cast<char&>(crc);
+
+ char &rc2 = (char&)*cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char &rc2 = const_cast<char&>(*cpc);
+
+ char ** const* const* ppcpcpc;
+ char ****ppppc = (char****)ppcpcpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char ****ppppc = const_cast<char****>(ppcpcpc);
+
+ char ***pppc = (char***)*(ppcpcpc);
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char ***pppc = const_cast<char***>(*(ppcpcpc));
+
+ char ***pppc2 = (char***)(*ppcpcpc);
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char ***pppc2 = const_cast<char***>(*ppcpcpc);
+
+ char *pc5 = (char*)(const char*)(cpv);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use const_cast [
+ // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: char *pc5 = const_cast<char*>(static_cast<const char*>(cpv));
+
+ int b1 = (int)b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: int b1 = static_cast<int>(b);
+ b1 = (const int&)b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: b1 = (const int&)b;
+
+ b1 = (int) b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ b1 = (int) b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ b1 = (int) (b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ b1 = (int) (b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ Y *pB = (Y*)pX;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ Y &rB = (Y&)*pX;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+
+ const char *pc3 = (const char*)cpv;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: const char *pc3 = static_cast<const char*>(cpv);
+
+ char *pc4 = (char*)cpv;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: char *pc4 = (char*)cpv;
+
+ b1 = (int)Enum1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: b1 = static_cast<int>(Enum1);
+
+ Enum e = (Enum)b1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: Enum e = static_cast<Enum>(b1);
+
+ e = (Enum)Enum1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = Enum1;
+
+ e = (Enum)e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = e;
+
+ e = (Enum) e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = e;
+
+ e = (Enum) (e);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = (e);
+
+ static const int kZero = 0;
+ (int)kZero;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} kZero;
+
+ int b2 = int(b);
+ int b3 = static_cast<double>(b);
+ int b4 = b;
+ double aa = a;
+ (void)b2;
+ return (void)g();
+}
+
+template <typename T>
+void template_function(T t, int n) {
+ int i = (int)t;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: int i = (int)t;
+ int j = (int)n;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant cast to the same type
+ // CHECK-FIXES: int j = n;
+}
+
+template <typename T>
+struct TemplateStruct {
+ void f(T t, int n) {
+ int k = (int)t;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast
+ // CHECK-FIXES: int k = (int)t;
+ int l = (int)n;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant cast to the same type
+ // CHECK-FIXES: int l = n;
+ }
+};
+
+void test_templates() {
+ template_function(1, 42);
+ template_function(1.0, 42);
+ TemplateStruct<int>().f(1, 42);
+ TemplateStruct<double>().f(1.0, 42);
+}
+
+extern "C" {
+void extern_c_code(const char *cpc) {
+ const char *cpc2 = (const char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant cast to the same type
+ // CHECK-FIXES: const char *cpc2 = cpc;
+ char *pc = (char*)cpc;
+}
+}
+
+#define CAST(type, value) (type)(value)
+void macros(double d) {
+ int i = CAST(int, d);
+}
+
+enum E { E1 = 1 };
+template <E e>
+struct A {
+ // Usage of template argument e = E1 is represented as (E)1 in the AST for
+ // some reason. We have a special treatment of this case to avoid warnings
+ // here.
+ static const E ee = e;
+};
+struct B : public A<E1> {};
+
+
+void overloaded_function();
+void overloaded_function(int);
+
+template<typename Fn>
+void g(Fn fn) {
+ fn();
+}
+
+void function_casts() {
+ typedef void (*FnPtrVoid)();
+ typedef void (&FnRefVoid)();
+ typedef void (&FnRefInt)(int);
+
+ g((void (*)())overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<void (*)()>(overloaded_function));
+ g((void (*)())&overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<void (*)()>(&overloaded_function));
+ g((void (&)())overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<void (&)()>(overloaded_function));
+
+ g((FnPtrVoid)overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<FnPtrVoid>(overloaded_function));
+ g((FnPtrVoid)&overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<FnPtrVoid>(&overloaded_function));
+ g((FnRefVoid)overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<FnRefVoid>(overloaded_function));
+
+ FnPtrVoid fn0 = (void (*)())&overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnPtrVoid fn0 = static_cast<void (*)()>(&overloaded_function);
+ FnPtrVoid fn1 = (void (*)())overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnPtrVoid fn1 = static_cast<void (*)()>(overloaded_function);
+ FnPtrVoid fn1a = (FnPtrVoid)overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnPtrVoid fn1a = static_cast<FnPtrVoid>(overloaded_function);
+ FnRefInt fn2 = (void (&)(int))overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnRefInt fn2 = static_cast<void (&)(int)>(overloaded_function);
+ auto fn3 = (void (*)())&overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto fn3 = static_cast<void (*)()>(&overloaded_function);
+ auto fn4 = (void (*)())overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto fn4 = static_cast<void (*)()>(overloaded_function);
+ auto fn5 = (void (&)(int))overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto fn5 = static_cast<void (&)(int)>(overloaded_function);
+
+ void (*fn6)() = (void (*)())&overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (*fn6)() = static_cast<void (*)()>(&overloaded_function);
+ void (*fn7)() = (void (*)())overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (*fn7)() = static_cast<void (*)()>(overloaded_function);
+ void (*fn8)() = (FnPtrVoid)overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (*fn8)() = static_cast<FnPtrVoid>(overloaded_function);
+ void (&fn9)(int) = (void (&)(int))overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (&fn9)(int) = static_cast<void (&)(int)>(overloaded_function);
+
+ void (*correct1)() = static_cast<void (*)()>(overloaded_function);
+ FnPtrVoid correct2 = static_cast<void (*)()>(&overloaded_function);
+ FnRefInt correct3 = static_cast<void (&)(int)>(overloaded_function);
+}
+
+struct S {
+ S(const char *);
+};
+struct ConvertibleToS {
+ operator S() const;
+};
+struct ConvertibleToSRef {
+ operator const S&() const;
+};
+
+void conversions() {
+ //auto s1 = (const S&)"";
+ // C HECK-MESSAGES: :[[@LINE-1]]:10: warning: C-style casts are discouraged; use static_cast [
+ // C HECK-FIXES: S s1 = static_cast<const S&>("");
+ auto s2 = (S)"";
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use constructor call syntax [
+ // CHECK-FIXES: auto s2 = S("");
+ auto s2a = (struct S)"";
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto s2a = static_cast<struct S>("");
+ auto s2b = (const S)"";
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // FIXME: This should be constructor call syntax: S("").
+ // CHECK-FIXES: auto s2b = static_cast<const S>("");
+ ConvertibleToS c;
+ auto s3 = (const S&)c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: auto s3 = (const S&)c;
+ // FIXME: This should be a static_cast.
+ // C HECK-FIXES: auto s3 = static_cast<const S&>(c);
+ auto s4 = (S)c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use constructor call syntax [
+ // CHECK-FIXES: auto s4 = S(c);
+ ConvertibleToSRef cr;
+ auto s5 = (const S&)cr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: auto s5 = (const S&)cr;
+ // FIXME: This should be a static_cast.
+ // C HECK-FIXES: auto s5 = static_cast<const S&>(cr);
+ auto s6 = (S)cr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use constructor call syntax [
+ // CHECK-FIXES: auto s6 = S(cr);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.mm
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.mm?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.mm (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-casting.mm Fri Oct 11 05:05:42 2019
@@ -0,0 +1,179 @@
+// RUN: clang-tidy %s -checks=-*,google-readability-casting -- \
+// RUN: -xobjective-c++ -fobjc-abi-version=2 -fobjc-arc | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+bool g() { return false; }
+
+enum Enum { Enum1 };
+struct X {};
+struct Y : public X {};
+
+void f(int a, double b, const char *cpc, const void *cpv, X *pX) {
+
+ typedef const char *Typedef1;
+ typedef const char *Typedef2;
+ Typedef1 t1;
+ (Typedef2)t1;
+ (const char*)t1;
+ (Typedef1)cpc;
+
+ typedef char Char;
+ char *pc;
+ Char *pChar = (Char*)pc;
+
+ (Char)*cpc;
+
+ (char)*pChar;
+
+ (const char*)cpv;
+
+ char *pc2 = (char*)(cpc + 33);
+
+ const char &crc = *cpc;
+ char &rc = (char&)crc;
+
+ char &rc2 = (char&)*cpc;
+
+ char ** const* const* ppcpcpc;
+ char ****ppppc = (char****)ppcpcpc;
+
+ char ***pppc = (char***)*(ppcpcpc);
+
+ char ***pppc2 = (char***)(*ppcpcpc);
+
+ char *pc5 = (char*)(const char*)(cpv);
+
+ int b1 = (int)b;
+ b1 = (const int&)b;
+
+ b1 = (int) b;
+
+ b1 = (int) b;
+
+ b1 = (int) (b);
+
+ b1 = (int) (b);
+
+ Y *pB = (Y*)pX;
+ Y &rB = (Y&)*pX;
+
+ const char *pc3 = (const char*)cpv;
+
+ char *pc4 = (char*)cpv;
+
+ b1 = (int)Enum1;
+
+ Enum e = (Enum)b1;
+
+ int b2 = int(b);
+ int b3 = static_cast<double>(b);
+ int b4 = b;
+ double aa = a;
+ (void)b2;
+ return (void)g();
+}
+
+template <typename T>
+void template_function(T t, int n) {
+ int i = (int)t;
+}
+
+template <typename T>
+struct TemplateStruct {
+ void f(T t, int n) {
+ int k = (int)t;
+ }
+};
+
+void test_templates() {
+ template_function(1, 42);
+ template_function(1.0, 42);
+ TemplateStruct<int>().f(1, 42);
+ TemplateStruct<double>().f(1.0, 42);
+}
+
+extern "C" {
+void extern_c_code(const char *cpc) {
+ char *pc = (char*)cpc;
+}
+}
+
+#define CAST(type, value) (type)(value)
+void macros(double d) {
+ int i = CAST(int, d);
+}
+
+enum E { E1 = 1 };
+template <E e>
+struct A {
+ // Usage of template argument e = E1 is represented as (E)1 in the AST for
+ // some reason. We have a special treatment of this case to avoid warnings
+ // here.
+ static const E ee = e;
+};
+struct B : public A<E1> {};
+
+
+void overloaded_function();
+void overloaded_function(int);
+
+template<typename Fn>
+void g(Fn fn) {
+ fn();
+}
+
+void function_casts() {
+ typedef void (*FnPtrVoid)();
+ typedef void (&FnRefVoid)();
+ typedef void (&FnRefInt)(int);
+
+ g((void (*)())overloaded_function);
+ g((void (*)())&overloaded_function);
+ g((void (&)())overloaded_function);
+
+ g((FnPtrVoid)overloaded_function);
+ g((FnPtrVoid)&overloaded_function);
+ g((FnRefVoid)overloaded_function);
+
+ FnPtrVoid fn0 = (void (*)())&overloaded_function;
+ FnPtrVoid fn1 = (void (*)())overloaded_function;
+ FnPtrVoid fn1a = (FnPtrVoid)overloaded_function;
+ FnRefInt fn2 = (void (&)(int))overloaded_function;
+ auto fn3 = (void (*)())&overloaded_function;
+ auto fn4 = (void (*)())overloaded_function;
+ auto fn5 = (void (&)(int))overloaded_function;
+
+ void (*fn6)() = (void (*)())&overloaded_function;
+ void (*fn7)() = (void (*)())overloaded_function;
+ void (*fn8)() = (FnPtrVoid)overloaded_function;
+ void (&fn9)(int) = (void (&)(int))overloaded_function;
+
+ void (*correct1)() = static_cast<void (*)()>(overloaded_function);
+ FnPtrVoid correct2 = static_cast<void (*)()>(&overloaded_function);
+ FnRefInt correct3 = static_cast<void (&)(int)>(overloaded_function);
+}
+
+struct S {
+ S(const char *);
+};
+struct ConvertibleToS {
+ operator S() const;
+};
+struct ConvertibleToSRef {
+ operator const S&() const;
+};
+
+void conversions() {
+ //auto s1 = (const S&)"";
+ auto s2 = (S)"";
+ auto s2a = (struct S)"";
+ auto s2b = (const S)"";
+ ConvertibleToS c;
+ auto s3 = (const S&)c;
+ auto s4 = (S)c;
+ ConvertibleToSRef cr;
+ auto s5 = (const S&)cr;
+ auto s6 = (S)cr;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-namespace-comments.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-namespace-comments.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-namespace-comments.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-namespace-comments.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,54 @@
+// RUN: %check_clang_tidy %s google-readability-namespace-comments %t
+
+namespace n1 {
+namespace n2 {
+
+
+void f(); // So that the namespace isn't empty.
+
+
+// CHECK-MESSAGES: :[[@LINE+4]]:1: warning: namespace 'n2' not terminated with a closing comment [google-readability-namespace-comments]
+// CHECK-MESSAGES: :[[@LINE-7]]:11: note: namespace 'n2' starts here
+// CHECK-MESSAGES: :[[@LINE+2]]:2: warning: namespace 'n1' not terminated with
+// CHECK-MESSAGES: :[[@LINE-10]]:11: note: namespace 'n1' starts here
+}}
+// CHECK-FIXES: } // namespace n2
+// CHECK-FIXES: } // namespace n1
+
+#define MACRO macro_expansion
+namespace MACRO {
+void f(); // So that the namespace isn't empty.
+// 1
+// 2
+// 3
+// 4
+// 5
+// 6
+// 7
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: namespace 'macro_expansion' not terminated with
+// CHECK-MESSAGES: :[[@LINE-10]]:11: note: namespace 'macro_expansion' starts here
+}
+// CHECK-FIXES: } // namespace macro_expansion
+
+namespace short1 {
+namespace short2 {
+// Namespaces covering 10 lines or fewer are exempt from this rule.
+
+
+
+
+
+}
+}
+
+namespace n3 {
+
+
+
+
+
+
+
+
+
+}; // namespace n3
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-nested-namespace-comments.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-nested-namespace-comments.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-nested-namespace-comments.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-nested-namespace-comments.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s google-readability-namespace-comments %t
+
+namespace n1::n2 {
+namespace n3 {
+
+// So that namespace is not empty.
+void f();
+
+
+// CHECK-MESSAGES: :[[@LINE+4]]:1: warning: namespace 'n3' not terminated with
+// CHECK-MESSAGES: :[[@LINE-7]]:11: note: namespace 'n3' starts here
+// CHECK-MESSAGES: :[[@LINE+2]]:2: warning: namespace 'n1::n2' not terminated with a closing comment [google-readability-namespace-comments]
+// CHECK-MESSAGES: :[[@LINE-10]]:11: note: namespace 'n1::n2' starts here
+}}
+// CHECK-FIXES: } // namespace n3
+// CHECK-FIXES: } // namespace n1::n2
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-todo.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-todo.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-todo.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-readability-todo.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s google-readability-todo %t -- -config="{User: 'some user'}" --
+
+// TODOfix this1
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this1
+
+// TODO fix this2
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this2
+
+// TODO fix this3
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this3
+
+// TODO: fix this4
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this4
+
+// TODO(clang)fix this5
+
+// TODO(foo):shave yaks
+// TODO(bar):
+// TODO(foo): paint bikeshed
+// TODO(b/12345): find the holy grail
+// TODO (b/12345): allow spaces before parentheses
+// TODO(asdf) allow missing semicolon
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int-std.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int-std.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int-std.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int-std.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s google-runtime-int %t -- \
+// RUN: -config='{CheckOptions: [ \
+// RUN: {key: google-runtime-int.UnsignedTypePrefix, value: "std::uint"}, \
+// RUN: {key: google-runtime-int.SignedTypePrefix, value: "std::int"}, \
+// RUN: {key: google-runtime-int.TypeSuffix, value: "_t"}, \
+// RUN: ]}'
+
+long a();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'std::int{{..}}_t'
+
+typedef unsigned long long uint64; // NOLINT
+
+long b(long = 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'std::int{{..}}_t'
+// CHECK-MESSAGES: [[@LINE-2]]:8: warning: consider replacing 'long' with 'std::int{{..}}_t'
+
+template <typename T>
+void tmpl() {
+ T i;
+}
+
+short bar(const short, unsigned short) {
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'short' with 'std::int16_t'
+// CHECK-MESSAGES: [[@LINE-2]]:17: warning: consider replacing 'short' with 'std::int16_t'
+// CHECK-MESSAGES: [[@LINE-3]]:24: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+ long double foo = 42;
+ uint64 qux = 42;
+ unsigned short port;
+
+ const unsigned short bar = 0;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+ long long *baar;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'std::int64_t'
+ const unsigned short &bara = bar;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+ long const long moo = 1;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'std::int64_t'
+ long volatile long wat = 42;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'std::int64_t'
+ unsigned long y;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long' with 'std::uint{{..}}_t'
+ unsigned long long **const *tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'std::uint64_t'
+ unsigned long long **const *&z = tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'std::uint64_t'
+ unsigned short porthole;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+
+ uint64 cast = (short)42;
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: consider replacing 'short' with 'std::int16_t'
+
+#define l long
+ l x;
+
+ tmpl<short>();
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: consider replacing 'short' with 'std::int16_t'
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,27 @@
+// RUN: clang-tidy -checks=-*,google-runtime-int %s -- -x c 2>&1 | not grep 'warning:\|error:'
+
+long a();
+
+long b(long x);
+
+short bar(const short q, unsigned short w) {
+ long double foo;
+ unsigned short port;
+
+ const unsigned short bar;
+ long long *baar;
+ const unsigned short bara;
+ long const long moo;
+ long volatile long wat;
+ unsigned long y;
+ unsigned long long **const *tmp;
+ unsigned short porthole;
+
+ unsigned cast;
+ cast = (short)42;
+ return q;
+}
+
+void qux() {
+ short port;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,91 @@
+// RUN: %check_clang_tidy %s google-runtime-int %t
+
+long a();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'int{{..}}'
+
+typedef unsigned long long uint64; // NOLINT
+
+long b(long = 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'int{{..}}'
+// CHECK-MESSAGES: [[@LINE-2]]:8: warning: consider replacing 'long' with 'int{{..}}'
+
+template <typename T>
+void tmpl() {
+ T i;
+}
+
+short bar(const short, unsigned short) {
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'short' with 'int16'
+// CHECK-MESSAGES: [[@LINE-2]]:17: warning: consider replacing 'short' with 'int16'
+// CHECK-MESSAGES: [[@LINE-3]]:24: warning: consider replacing 'unsigned short' with 'uint16'
+ long double foo = 42;
+ uint64 qux = 42;
+ unsigned short port;
+
+ const unsigned short bar = 0;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'uint16'
+ long long *baar;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'int64'
+ const unsigned short &bara = bar;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'uint16'
+ long const long moo = 1;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'int64'
+ long volatile long wat = 42;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'int64'
+ unsigned long y;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long' with 'uint{{..}}'
+ unsigned long long **const *tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'uint64'
+ unsigned long long **const *&z = tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'uint64'
+ unsigned short porthole;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned short' with 'uint16'
+
+ uint64 cast = (short)42;
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: consider replacing 'short' with 'int16'
+
+#define l long
+ l x;
+
+ tmpl<short>();
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: consider replacing 'short' with 'int16'
+ return 0;
+}
+
+void p(unsigned short port);
+
+void qux() {
+ short port;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'short' with 'int16'
+}
+
+// FIXME: This shouldn't warn, as UD-literal operators require one of a handful
+// of types as an argument.
+struct some_value {};
+constexpr some_value operator"" _some_literal(unsigned long long int i);
+// CHECK-MESSAGES: [[@LINE-1]]:47: warning: consider replacing 'unsigned long long'
+
+struct A { A& operator=(const A&); };
+class B { A a[0]; };
+
+void fff() {
+ B a, b;
+ a = b;
+}
+
+__attribute__((__format__ (__printf__, 1, 2)))
+void myprintf(const char* s, ...);
+
+void doprint_no_warning() {
+ uint64 foo = 23;
+ myprintf("foo %lu %lu", (unsigned long)42, (unsigned long)foo);
+}
+
+void myprintf_no_attribute(const char* s, ...);
+
+void doprint_warning() {
+ uint64 foo = 23;
+ myprintf_no_attribute("foo %lu %lu", (unsigned long)42, (unsigned long)foo);
+// CHECK-MESSAGES: [[@LINE-1]]:41: warning: consider replacing 'unsigned long'
+// CHECK-MESSAGES: [[@LINE-2]]:60: warning: consider replacing 'unsigned long'
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.m
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.m?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.m (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-int.m Fri Oct 11 05:05:42 2019
@@ -0,0 +1,32 @@
+// RUN: clang-tidy -checks=-*,google-runtime-int %s 2>&1 -- | count 0
+// RUN: clang-tidy -checks=-*,google-runtime-int %s 2>&1 -- -x objective-c++ | count 0
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+
+ at interface NSString
+ at property(readonly) NSInteger integerValue;
+ at property(readonly) long long longLongValue;
+ at property(readonly) NSUInteger length;
+ at end
+
+NSInteger Foo(NSString *s) {
+ return [s integerValue];
+}
+
+long long Bar(NSString *s) {
+ return [s longLongValue];
+}
+
+NSUInteger Baz(NSString *s) {
+ return [s length];
+}
+
+unsigned short NSSwapShort(unsigned short inv);
+
+long DoSomeMath(long a, short b) {
+ short c = NSSwapShort(b);
+ long a2 = a * 5L;
+ return a2 + c;
+}
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-references.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-references.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-references.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-runtime-references.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,155 @@
+// RUN: %check_clang_tidy %s google-runtime-references %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: google-runtime-references.WhiteListTypes, \
+// RUN: value: 'whitelist::A; whitelist::B'}]}"
+
+int a;
+int &b = a;
+int *c;
+void f1(int a);
+void f2(int *b);
+void f3(const int &c);
+void f4(int const &d);
+
+// Don't warn on implicit operator= in c++11 mode.
+class A {
+ virtual void f() {}
+};
+// Don't warn on rvalue-references.
+struct A2 {
+ A2(A2&&) = default;
+ void f(A2&&) {}
+};
+
+// Don't warn on iostream parameters.
+namespace xxx {
+class istream { };
+class ostringstream { };
+}
+void g1(xxx::istream &istr);
+void g1(xxx::ostringstream &istr);
+
+void g1(int &a);
+// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', make it const or use a pointer [google-runtime-references]
+
+struct s {};
+void g2(int a, int b, s c, s &d);
+// CHECK-MESSAGES: [[@LINE-1]]:31: warning: non-const reference parameter 'd', {{.*}}
+
+typedef int &ref;
+void g3(ref a);
+// CHECK-MESSAGES: [[@LINE-1]]:13: warning: non-const reference {{.*}}
+
+void g4(int &a, int &b, int &);
+// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', {{.*}}
+// CHECK-MESSAGES: [[@LINE-2]]:22: warning: non-const reference parameter 'b', {{.*}}
+// CHECK-MESSAGES: [[@LINE-3]]:30: warning: non-const reference parameter at index 2, {{.*}}
+
+class B {
+ B(B& a) {}
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: non-const reference {{.*}}
+ virtual void f(int &a) {}
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: non-const reference {{.*}}
+ void g(int &b);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: non-const reference {{.*}}
+
+ // Don't warn on the parameter of stream extractors defined as members.
+ B& operator>>(int& val) { return *this; }
+};
+
+// Only warn on the first declaration of each function to reduce duplicate
+// warnings.
+void B::g(int &b) {}
+
+// Don't warn on the first parameter of stream inserters.
+A& operator<<(A& s, int&) { return s; }
+// CHECK-MESSAGES: [[@LINE-1]]:25: warning: non-const reference parameter at index 1, {{.*}}
+
+// Don't warn on either parameter of stream extractors. Both need to be
+// non-const references by convention.
+A& operator>>(A& input, int& val) { return input; }
+
+// Don't warn on lambdas.
+auto lambda = [] (int&) {};
+
+// Don't warn on typedefs, as we'll warn on the function itself.
+typedef int (*fp)(int &);
+
+// Don't warn on function references.
+typedef void F();
+void g5(const F& func) {}
+void g6(F& func) {}
+
+template<typename T>
+void g7(const T& t) {}
+
+template<typename T>
+void g8(T t) {}
+
+void f5() {
+ g5(f5);
+ g6(f5);
+ g7(f5);
+ g7<F&>(f5);
+ g8(f5);
+ g8<F&>(f5);
+}
+
+// Don't warn on dependent types.
+template<typename T>
+void g9(T& t) {}
+template<typename T>
+void g10(T t) {}
+
+void f6() {
+ int i;
+ float f;
+ g9<int>(i);
+ g9<const int>(i);
+ g9<int&>(i);
+ g10<int&>(i);
+ g10<float&>(f);
+}
+
+// Warn only on the overridden methods from the base class, as the child class
+// only implements the interface.
+class C : public B {
+ C();
+ virtual void f(int &a) {}
+};
+
+// Don't warn on operator<< with streams-like interface.
+A& operator<<(A& s, int) { return s; }
+
+// Don't warn on swap().
+void swap(C& c1, C& c2) {}
+
+// Don't warn on standalone operator++, operator--, operator+=, operator-=,
+// operator*=, etc. that all need non-const references to be functional.
+A& operator++(A& a) { return a; }
+A operator++(A& a, int) { return a; }
+A& operator--(A& a) { return a; }
+A operator--(A& a, int) { return a; }
+A& operator+=(A& a, const A& b) { return a; }
+A& operator-=(A& a, const A& b) { return a; }
+A& operator*=(A& a, const A& b) { return a; }
+A& operator/=(A& a, const A& b) { return a; }
+A& operator%=(A& a, const A& b) { return a; }
+A& operator<<=(A& a, const A& b) { return a; }
+A& operator>>=(A& a, const A& b) { return a; }
+A& operator|=(A& a, const A& b) { return a; }
+A& operator^=(A& a, const A& b) { return a; }
+A& operator&=(A& a, const A& b) { return a; }
+
+namespace whitelist {
+class A {};
+class B {};
+void f7(A &);
+void f8(B &);
+}
+void f9(whitelist::A &);
+void f10(whitelist::B &);
+
+#define DEFINE_F(name) void name(int& a)
+
+DEFINE_F(func) {}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/google-upgrade-googletest-case.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/google-upgrade-googletest-case.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/google-upgrade-googletest-case.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/google-upgrade-googletest-case.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,1016 @@
+// RUN: %check_clang_tidy %s google-upgrade-googletest-case %t -- -- -I%S/Inputs
+// RUN: %check_clang_tidy -check-suffix=NOSUITE %s google-upgrade-googletest-case %t -- -- -DNOSUITE -I%S/Inputs/gtest/nosuite
+
+#include "gtest/gtest.h"
+
+// When including a version of googletest without the replacement names, this
+// check should not produce any diagnostics. The following dummy fix is present
+// because `check_clang_tidy.py` requires at least one warning, fix or note.
+void Dummy() {}
+// CHECK-FIXES-NOSUITE: void Dummy() {}
+
+// ----------------------------------------------------------------------------
+// Macros
+
+TYPED_TEST_CASE(FooTest, FooTypes);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: Google Test APIs named with 'case' are deprecated; use equivalent APIs named with 'suite'
+// CHECK-FIXES: TYPED_TEST_SUITE(FooTest, FooTypes);
+TYPED_TEST_CASE_P(FooTest);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: TYPED_TEST_SUITE_P(FooTest);
+REGISTER_TYPED_TEST_CASE_P(FooTest, FooTestName);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: REGISTER_TYPED_TEST_SUITE_P(FooTest, FooTestName);
+INSTANTIATE_TYPED_TEST_CASE_P(FooPrefix, FooTest, FooTypes);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: INSTANTIATE_TYPED_TEST_SUITE_P(FooPrefix, FooTest, FooTypes);
+
+#ifdef TYPED_TEST_CASE
+// CHECK-MESSAGES: [[@LINE-1]]:2: warning: Google Test APIs named with 'case'
+#undef TYPED_TEST_CASE
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+#define TYPED_TEST_CASE(CaseName, Types, ...)
+#endif
+
+#ifdef TYPED_TEST_CASE_P
+// CHECK-MESSAGES: [[@LINE-1]]:2: warning: Google Test APIs named with 'case'
+#undef TYPED_TEST_CASE_P
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+#define TYPED_TEST_CASE_P(SuiteName)
+#endif
+
+#ifdef REGISTER_TYPED_TEST_CASE_P
+// CHECK-MESSAGES: [[@LINE-1]]:2: warning: Google Test APIs named with 'case'
+#undef REGISTER_TYPED_TEST_CASE_P
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+#define REGISTER_TYPED_TEST_CASE_P(SuiteName, ...)
+#endif
+
+#ifdef INSTANTIATE_TYPED_TEST_CASE_P
+// CHECK-MESSAGES: [[@LINE-1]]:2: warning: Google Test APIs named with 'case'
+#undef INSTANTIATE_TYPED_TEST_CASE_P
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, SuiteName, Types, ...)
+#endif
+
+TYPED_TEST_CASE(FooTest, FooTypes);
+TYPED_TEST_CASE_P(FooTest);
+REGISTER_TYPED_TEST_CASE_P(FooTest, FooTestName);
+INSTANTIATE_TYPED_TEST_CASE_P(FooPrefix, FooTest, FooTypes);
+
+// ----------------------------------------------------------------------------
+// testing::Test
+
+class FooTest : public testing::Test {
+public:
+ static void SetUpTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: static void SetUpTestSuite();
+ static void TearDownTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: static void TearDownTestSuite();
+};
+
+void FooTest::SetUpTestCase() {}
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: void FooTest::SetUpTestSuite() {}
+
+void FooTest::TearDownTestCase() {}
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: void FooTest::TearDownTestSuite() {}
+
+template <typename T> class FooTypedTest : public testing::Test {
+public:
+ static void SetUpTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: static void SetUpTestSuite();
+ static void TearDownTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: static void TearDownTestSuite();
+};
+
+template <typename T> void FooTypedTest<T>::SetUpTestCase() {}
+// CHECK-MESSAGES: [[@LINE-1]]:45: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: void FooTypedTest<T>::SetUpTestSuite() {}
+
+template <typename T> void FooTypedTest<T>::TearDownTestCase() {}
+// CHECK-MESSAGES: [[@LINE-1]]:45: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: void FooTypedTest<T>::TearDownTestSuite() {}
+
+class BarTest : public testing::Test {
+public:
+ using Test::SetUpTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using Test::SetUpTestSuite;
+ using Test::TearDownTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using Test::TearDownTestSuite;
+};
+
+class BarTest2 : public FooTest {
+public:
+ using FooTest::SetUpTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using FooTest::SetUpTestSuite;
+ using FooTest::TearDownTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using FooTest::TearDownTestSuite;
+};
+
+// If a derived type already has the replacements, we only provide a warning
+// since renaming or deleting the old declarations may not be safe.
+class BarTest3 : public testing::Test {
+ public:
+ static void SetUpTestCase() {}
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ static void SetUpTestSuite() {}
+
+ static void TearDownTestCase() {}
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ static void TearDownTestSuite() {}
+};
+
+namespace nesting_ns {
+namespace testing {
+
+class Test {
+public:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+};
+
+} // namespace testing
+
+void Test() {
+ testing::Test::SetUpTestCase();
+ testing::Test::TearDownTestCase();
+}
+
+} // namespace nesting_ns
+
+template <typename T>
+void testInstantiationOnlyWarns() {
+ T::SetUpTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:6: warning: Google Test APIs named with 'case'
+ T::TearDownTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:6: warning: Google Test APIs named with 'case'
+}
+
+#define SET_UP_TEST_CASE_MACRO_REPLACE SetUpTestCase
+#define TEST_SET_UP_TEST_CASE_MACRO_WARN_ONLY ::testing::Test::SetUpTestCase
+
+void setUpTearDownCallAndReference() {
+ testing::Test::SetUpTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::Test::SetUpTestSuite();
+ FooTest::SetUpTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: FooTest::SetUpTestSuite();
+
+ testing::Test::TearDownTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::Test::TearDownTestSuite();
+ FooTest::TearDownTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: FooTest::TearDownTestSuite();
+
+ auto F = &testing::Test::SetUpTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F = &testing::Test::SetUpTestSuite;
+ F = &testing::Test::TearDownTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: F = &testing::Test::TearDownTestSuite;
+ F = &FooTest::SetUpTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: F = &FooTest::SetUpTestSuite;
+ F = &FooTest::TearDownTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: F = &FooTest::TearDownTestSuite;
+
+ using MyTest = testing::Test;
+ MyTest::SetUpTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: MyTest::SetUpTestSuite();
+ MyTest::TearDownTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: MyTest::TearDownTestSuite();
+
+ BarTest3::SetUpTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: BarTest3::SetUpTestSuite();
+ BarTest3::TearDownTestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: BarTest3::TearDownTestSuite();
+
+ testInstantiationOnlyWarns<testing::Test>();
+
+ testing::Test::SET_UP_TEST_CASE_MACRO_REPLACE();
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::Test::SetUpTestSuite();
+ TEST_SET_UP_TEST_CASE_MACRO_WARN_ONLY();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+}
+
+// ----------------------------------------------------------------------------
+// testing::TestInfo
+
+class FooTestInfo : public testing::TestInfo {
+public:
+ const char *test_case_name() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const char *test_suite_name() const;
+};
+
+const char *FooTestInfo::test_case_name() const {}
+// CHECK-MESSAGES: [[@LINE-1]]:26: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: const char *FooTestInfo::test_suite_name() const {}
+
+class BarTestInfo : public testing::TestInfo {
+public:
+ using TestInfo::test_case_name;
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using TestInfo::test_suite_name;
+};
+
+class BarTestInfo2 : public FooTestInfo {
+public:
+ using FooTestInfo::test_case_name;
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using FooTestInfo::test_suite_name;
+};
+
+class BarTestInfo3 : public testing::TestInfo {
+ public:
+ const char* test_case_name() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: Google Test APIs named with 'case'
+ const char* test_suite_name() const;
+};
+
+namespace nesting_ns {
+namespace testing {
+
+class TestInfo {
+public:
+ const char *test_case_name() const;
+};
+
+} // namespace testing
+
+void FuncInfo() {
+ testing::TestInfo t;
+ (void)t.test_case_name();
+}
+
+} // namespace nesting_ns
+
+template <typename T>
+void testInfoInstantiationOnlyWarns() {
+ T t;
+ (void)t.test_case_name();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+}
+
+#define TEST_CASE_NAME_MACRO_REPLACE test_case_name
+#define TEST_CASE_NAME_MACRO_WARN_ONLY testing::TestInfo().test_case_name
+
+void testInfoCallAndReference() {
+ (void)testing::TestInfo().test_case_name();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::TestInfo().test_suite_name();
+ (void)FooTestInfo().test_case_name();
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)FooTestInfo().test_suite_name();
+ auto F1 = &testing::TestInfo::test_case_name;
+ // CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F1 = &testing::TestInfo::test_suite_name;
+ auto F2 = &FooTestInfo::test_case_name;
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F2 = &FooTestInfo::test_suite_name;
+ using MyTestInfo = testing::TestInfo;
+ (void)MyTestInfo().test_case_name();
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)MyTestInfo().test_suite_name();
+ (void)BarTestInfo3().test_case_name();
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)BarTestInfo3().test_suite_name();
+
+ testInfoInstantiationOnlyWarns<testing::TestInfo>();
+
+ (void)testing::TestInfo().TEST_CASE_NAME_MACRO_REPLACE();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::TestInfo().test_suite_name();
+ (void)TEST_CASE_NAME_MACRO_WARN_ONLY();
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: Google Test APIs named with 'case'
+}
+
+// ----------------------------------------------------------------------------
+// testing::TestEventListener
+
+class FooTestEventListener : public testing::TestEventListener {
+public:
+ void OnTestCaseStart(const testing::TestCase &) override;
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+ // CHECK-MESSAGES: [[@LINE-2]]:39: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: void OnTestSuiteStart(const testing::TestSuite &) override;
+ void OnTestCaseEnd(const testing::TestCase &) override;
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+ // CHECK-MESSAGES: [[@LINE-2]]:37: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: void OnTestSuiteEnd(const testing::TestSuite &) override;
+};
+
+void FooTestEventListener::OnTestCaseStart(const testing::TestCase &) {}
+// CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+// CHECK-MESSAGES: [[@LINE-2]]:59: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: void FooTestEventListener::OnTestSuiteStart(const testing::TestSuite &) {}
+
+void FooTestEventListener::OnTestCaseEnd(const testing::TestCase &) {}
+// CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+// CHECK-MESSAGES: [[@LINE-2]]:57: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: void FooTestEventListener::OnTestSuiteEnd(const testing::TestSuite &) {}
+
+class BarTestEventListener : public testing::TestEventListener {
+public:
+ using TestEventListener::OnTestCaseStart;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using TestEventListener::OnTestSuiteStart;
+ using TestEventListener::OnTestCaseEnd;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using TestEventListener::OnTestSuiteEnd;
+};
+
+class BarTestEventListener2 : public BarTestEventListener {
+public:
+ using BarTestEventListener::OnTestCaseStart;
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarTestEventListener::OnTestSuiteStart;
+ using BarTestEventListener::OnTestCaseEnd;
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarTestEventListener::OnTestSuiteEnd;
+};
+
+#ifndef NOSUITE
+
+class BarTestEventListener3 : public testing::TestEventListener {
+public:
+ void OnTestCaseStart(const testing::TestSuite &) override;
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+ void OnTestSuiteStart(const testing::TestSuite &) override;
+
+ void OnTestCaseEnd(const testing::TestSuite &) override;
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: Google Test APIs named with 'case'
+ void OnTestSuiteEnd(const testing::TestSuite &) override;
+};
+
+#endif
+
+namespace nesting_ns {
+namespace testing {
+
+class TestEventListener {
+public:
+ virtual void OnTestCaseStart(const ::testing::TestCase &);
+ // CHECK-MESSAGES: [[@LINE-1]]:49: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: virtual void OnTestCaseStart(const ::testing::TestSuite &);
+ virtual void OnTestCaseEnd(const ::testing::TestCase &);
+ // CHECK-MESSAGES: [[@LINE-1]]:47: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: virtual void OnTestCaseEnd(const ::testing::TestSuite &);
+};
+
+} // namespace testing
+
+void FuncTestEventListener(::testing::TestCase &Case) {
+ // CHECK-MESSAGES: [[@LINE-1]]:39: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: void FuncTestEventListener(::testing::TestSuite &Case) {
+ testing::TestEventListener().OnTestCaseStart(Case);
+ testing::TestEventListener().OnTestCaseEnd(Case);
+}
+
+} // namespace nesting_ns
+
+#ifndef NOSUITE
+
+template <typename T>
+void testEventListenerInstantiationOnlyWarns() {
+ T().OnTestCaseStart(testing::TestSuite());
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ T().OnTestCaseEnd(testing::TestSuite());
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+}
+
+#endif
+
+#define ON_TEST_CASE_START_MACRO_REPLACE OnTestCaseStart
+#define ON_TEST_CASE_START_MACRO_WARN_ONLY \
+ testing::TestEventListener().OnTestCaseStart
+
+#define ON_TEST_CASE_END_MACRO_REPLACE OnTestCaseEnd
+#define ON_TEST_CASE_END_MACRO_WARN_ONLY \
+ testing::TestEventListener().OnTestCaseEnd
+
+void testEventListenerCallAndReference(testing::TestCase &Case) {
+ // CHECK-MESSAGES: [[@LINE-1]]:49: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: void testEventListenerCallAndReference(testing::TestSuite &Case) {
+ testing::TestEventListener().OnTestCaseStart(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:32: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestEventListener().OnTestSuiteStart(Case);
+ testing::TestEventListener().OnTestCaseEnd(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:32: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestEventListener().OnTestSuiteEnd(Case);
+
+ FooTestEventListener().OnTestCaseStart(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:26: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: FooTestEventListener().OnTestSuiteStart(Case);
+ FooTestEventListener().OnTestCaseEnd(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:26: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: FooTestEventListener().OnTestSuiteEnd(Case);
+
+ auto F1 = &testing::TestEventListener::OnTestCaseStart;
+ // CHECK-MESSAGES: [[@LINE-1]]:42: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F1 = &testing::TestEventListener::OnTestSuiteStart;
+ F1 = &testing::TestEventListener::OnTestCaseEnd;
+ // CHECK-MESSAGES: [[@LINE-1]]:37: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: F1 = &testing::TestEventListener::OnTestSuiteEnd;
+
+ auto F2 = &FooTestEventListener::OnTestCaseStart;
+ // CHECK-MESSAGES: [[@LINE-1]]:36: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F2 = &FooTestEventListener::OnTestSuiteStart;
+ F2 = &FooTestEventListener::OnTestCaseEnd;
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: F2 = &FooTestEventListener::OnTestSuiteEnd;
+
+#ifndef NOSUITE
+
+ BarTestEventListener3().OnTestCaseStart(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: BarTestEventListener3().OnTestSuiteStart(Case);
+ BarTestEventListener3().OnTestCaseEnd(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: BarTestEventListener3().OnTestSuiteEnd(Case);
+
+ testEventListenerInstantiationOnlyWarns<testing::TestEventListener>();
+
+#endif
+
+ testing::TestEventListener().ON_TEST_CASE_START_MACRO_REPLACE(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:32: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestEventListener().OnTestSuiteStart(Case);
+ ON_TEST_CASE_START_MACRO_WARN_ONLY(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+
+ testing::TestEventListener().ON_TEST_CASE_END_MACRO_REPLACE(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:32: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestEventListener().OnTestSuiteEnd(Case);
+ ON_TEST_CASE_END_MACRO_WARN_ONLY(Case);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+}
+
+// ----------------------------------------------------------------------------
+// testing::UnitTest
+
+class FooUnitTest : public testing::UnitTest {
+public:
+ testing::TestCase *current_test_case() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: Google Test APIs named with 'case'
+ // CHECK-MESSAGES: [[@LINE-2]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestSuite *current_test_suite() const;
+ int successful_test_case_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: int successful_test_suite_count() const;
+ int failed_test_case_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: int failed_test_suite_count() const;
+ int total_test_case_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: int total_test_suite_count() const;
+ int test_case_to_run_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: int test_suite_to_run_count() const;
+ const testing::TestCase *GetTestCase(int) const;
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+ // CHECK-MESSAGES: [[@LINE-2]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const testing::TestSuite *GetTestSuite(int) const;
+};
+
+testing::TestCase *FooUnitTest::current_test_case() const {}
+// CHECK-MESSAGES: [[@LINE-1]]:10: warning: Google Test APIs named with 'case'
+// CHECK-MESSAGES: [[@LINE-2]]:33: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: testing::TestSuite *FooUnitTest::current_test_suite() const {}
+int FooUnitTest::successful_test_case_count() const {}
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: int FooUnitTest::successful_test_suite_count() const {}
+int FooUnitTest::failed_test_case_count() const {}
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: int FooUnitTest::failed_test_suite_count() const {}
+int FooUnitTest::total_test_case_count() const {}
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: int FooUnitTest::total_test_suite_count() const {}
+int FooUnitTest::test_case_to_run_count() const {}
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: int FooUnitTest::test_suite_to_run_count() const {}
+const testing::TestCase *FooUnitTest::GetTestCase(int) const {}
+// CHECK-MESSAGES: [[@LINE-1]]:16: warning: Google Test APIs named with 'case'
+// CHECK-MESSAGES: [[@LINE-2]]:39: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: const testing::TestSuite *FooUnitTest::GetTestSuite(int) const {}
+
+// Type derived from testing::TestCase
+class BarUnitTest : public testing::UnitTest {
+public:
+ using testing::UnitTest::current_test_case;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using testing::UnitTest::current_test_suite;
+ using testing::UnitTest::successful_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using testing::UnitTest::successful_test_suite_count;
+ using testing::UnitTest::failed_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using testing::UnitTest::failed_test_suite_count;
+ using testing::UnitTest::total_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using testing::UnitTest::total_test_suite_count;
+ using testing::UnitTest::test_case_to_run_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using testing::UnitTest::test_suite_to_run_count;
+ using testing::UnitTest::GetTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using testing::UnitTest::GetTestSuite;
+};
+
+class BarUnitTest2 : public BarUnitTest {
+ using BarUnitTest::current_test_case;
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarUnitTest::current_test_suite;
+ using BarUnitTest::successful_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarUnitTest::successful_test_suite_count;
+ using BarUnitTest::failed_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarUnitTest::failed_test_suite_count;
+ using BarUnitTest::total_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarUnitTest::total_test_suite_count;
+ using BarUnitTest::test_case_to_run_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarUnitTest::test_suite_to_run_count;
+ using BarUnitTest::GetTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: using BarUnitTest::GetTestSuite;
+};
+
+#ifndef NOSUITE
+
+class BarUnitTest3 : public testing::UnitTest {
+ testing::TestSuite *current_test_case() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ int successful_test_case_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ int failed_test_case_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ int total_test_case_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ int test_case_to_run_count() const;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ const testing::TestSuite *GetTestCase(int) const;
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+
+ testing::TestSuite *current_test_suite() const;
+ int successful_test_suite_count() const;
+ int failed_test_suite_count() const;
+ int total_test_suite_count() const;
+ int test_suite_to_run_count() const;
+ const testing::TestSuite *GetTestSuite(int) const;
+};
+
+#endif
+
+namespace nesting_ns {
+namespace testing {
+
+class TestSuite;
+
+class UnitTest {
+public:
+ TestSuite *current_test_case() const;
+ int successful_test_case_count() const;
+ int failed_test_case_count() const;
+ int total_test_case_count() const;
+ int test_case_to_run_count() const;
+ const TestSuite *GetTestCase(int) const;
+};
+
+} // namespace testing
+
+void FuncUnitTest() {
+ testing::UnitTest t;
+ (void)t.current_test_case();
+ (void)t.successful_test_case_count();
+ (void)t.failed_test_case_count();
+ (void)t.total_test_case_count();
+ (void)t.test_case_to_run_count();
+ (void)t.GetTestCase(0);
+}
+
+} // namespace nesting_ns
+
+template <typename T>
+void unitTestInstantiationOnlyWarns() {
+ T t;
+ (void)t.current_test_case();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+ (void)t.successful_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+ (void)t.failed_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+ (void)t.total_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+ (void)t.test_case_to_run_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+ (void)t.GetTestCase(0);
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+}
+
+#define UNIT_TEST_NAME_MACRO_REPLACE1 current_test_case
+#define UNIT_TEST_NAME_MACRO_REPLACE2 successful_test_case_count
+#define UNIT_TEST_NAME_MACRO_REPLACE3 failed_test_case_count
+#define UNIT_TEST_NAME_MACRO_REPLACE4 total_test_case_count
+#define UNIT_TEST_NAME_MACRO_REPLACE5 test_case_to_run_count
+#define UNIT_TEST_NAME_MACRO_REPLACE6 GetTestCase
+#define UNIT_TEST_NAME_MACRO_WARN_ONLY1 testing::UnitTest().current_test_case
+#define UNIT_TEST_NAME_MACRO_WARN_ONLY2 \
+ testing::UnitTest().successful_test_case_count
+#define UNIT_TEST_NAME_MACRO_WARN_ONLY3 \
+ testing::UnitTest().failed_test_case_count
+#define UNIT_TEST_NAME_MACRO_WARN_ONLY4 \
+ testing::UnitTest().total_test_case_count
+#define UNIT_TEST_NAME_MACRO_WARN_ONLY5 \
+ testing::UnitTest().test_case_to_run_count
+#define UNIT_TEST_NAME_MACRO_WARN_ONLY6 testing::UnitTest().GetTestCase
+
+void unitTestCallAndReference() {
+ (void)testing::UnitTest().current_test_case();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().current_test_suite();
+ (void)testing::UnitTest().successful_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().successful_test_suite_count();
+ (void)testing::UnitTest().failed_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().failed_test_suite_count();
+ (void)testing::UnitTest().total_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().total_test_suite_count();
+ (void)testing::UnitTest().test_case_to_run_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().test_suite_to_run_count();
+ (void)testing::UnitTest().GetTestCase(0);
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().GetTestSuite(0);
+
+ (void)FooUnitTest().current_test_case();
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)FooUnitTest().current_test_suite();
+ (void)FooUnitTest().successful_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)FooUnitTest().successful_test_suite_count();
+ (void)FooUnitTest().failed_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)FooUnitTest().failed_test_suite_count();
+ (void)FooUnitTest().total_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)FooUnitTest().total_test_suite_count();
+ (void)FooUnitTest().test_case_to_run_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)FooUnitTest().test_suite_to_run_count();
+ (void)FooUnitTest().GetTestCase(0);
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)FooUnitTest().GetTestSuite(0);
+
+ auto U1 = &testing::UnitTest::current_test_case;
+ // CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto U1 = &testing::UnitTest::current_test_suite;
+ auto U2 = &testing::UnitTest::successful_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto U2 = &testing::UnitTest::successful_test_suite_count;
+ auto U3 = &testing::UnitTest::failed_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto U3 = &testing::UnitTest::failed_test_suite_count;
+ auto U4 = &testing::UnitTest::total_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto U4 = &testing::UnitTest::total_test_suite_count;
+ auto U5 = &testing::UnitTest::test_case_to_run_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto U5 = &testing::UnitTest::test_suite_to_run_count;
+ auto U6 = &testing::UnitTest::GetTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto U6 = &testing::UnitTest::GetTestSuite;
+
+ auto F1 = &FooUnitTest::current_test_case;
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F1 = &FooUnitTest::current_test_suite;
+ auto F2 = &FooUnitTest::successful_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F2 = &FooUnitTest::successful_test_suite_count;
+ auto F3 = &FooUnitTest::failed_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F3 = &FooUnitTest::failed_test_suite_count;
+ auto F4 = &FooUnitTest::total_test_case_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F4 = &FooUnitTest::total_test_suite_count;
+ auto F5 = &FooUnitTest::test_case_to_run_count;
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F5 = &FooUnitTest::test_suite_to_run_count;
+ auto F6 = &FooUnitTest::GetTestCase;
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: auto F6 = &FooUnitTest::GetTestSuite;
+
+ using MyUnitTest = testing::UnitTest;
+ (void)MyUnitTest().current_test_case();
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)MyUnitTest().current_test_suite();
+ (void)MyUnitTest().successful_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)MyUnitTest().successful_test_suite_count();
+ (void)MyUnitTest().failed_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)MyUnitTest().failed_test_suite_count();
+ (void)MyUnitTest().total_test_case_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)MyUnitTest().total_test_suite_count();
+ (void)MyUnitTest().test_case_to_run_count();
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)MyUnitTest().test_suite_to_run_count();
+ (void)MyUnitTest().GetTestCase(0);
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)MyUnitTest().GetTestSuite(0);
+
+ unitTestInstantiationOnlyWarns<testing::UnitTest>();
+
+ (void)testing::UnitTest().UNIT_TEST_NAME_MACRO_REPLACE1();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().current_test_suite();
+ (void)testing::UnitTest().UNIT_TEST_NAME_MACRO_REPLACE2();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().successful_test_suite_count();
+ (void)testing::UnitTest().UNIT_TEST_NAME_MACRO_REPLACE3();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().failed_test_suite_count();
+ (void)testing::UnitTest().UNIT_TEST_NAME_MACRO_REPLACE4();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().total_test_suite_count();
+ (void)testing::UnitTest().UNIT_TEST_NAME_MACRO_REPLACE5();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().test_suite_to_run_count();
+ (void)testing::UnitTest().UNIT_TEST_NAME_MACRO_REPLACE6(0);
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)testing::UnitTest().GetTestSuite(0);
+
+ UNIT_TEST_NAME_MACRO_WARN_ONLY1();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+ UNIT_TEST_NAME_MACRO_WARN_ONLY2();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+ UNIT_TEST_NAME_MACRO_WARN_ONLY3();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+ UNIT_TEST_NAME_MACRO_WARN_ONLY4();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+ UNIT_TEST_NAME_MACRO_WARN_ONLY5();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+ UNIT_TEST_NAME_MACRO_WARN_ONLY6(0);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+}
+
+// ----------------------------------------------------------------------------
+// testing::TestCase
+
+template <typename T>
+void TestCaseInTemplate() {
+ T t;
+
+ testing::TestCase Case;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestSuite Case;
+}
+
+#define TEST_CASE_CAN_FIX TestCase
+#define TEST_CASE_WARN_ONLY testing::TestCase
+
+const testing::TestCase *testCaseUses(const testing::TestCase &Case) {
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: Google Test APIs named with 'case'
+ // CHECK-MESSAGES: [[@LINE-2]]:54: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const testing::TestSuite *testCaseUses(const testing::TestSuite &Case) {
+
+ // No change for implicit declarations:
+ auto Lambda = [&Case]() {};
+
+ TestCaseInTemplate<testing::TestCase>();
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: TestCaseInTemplate<testing::TestSuite>();
+
+ testing::TEST_CASE_CAN_FIX C1;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestSuite C1;
+ TEST_CASE_WARN_ONLY C2;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+
+ (void)new testing::TestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)new testing::TestSuite();
+ const testing::TestCase *Result = &Case;
+ // CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const testing::TestSuite *Result = &Case;
+ return Result;
+}
+
+struct TestCaseHolder {
+ testing::TestCase Case;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: testing::TestSuite Case;
+};
+
+class MyTest : public testing::TestCase {};
+// CHECK-MESSAGES: [[@LINE-1]]:32: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: class MyTest : public testing::TestSuite {};
+
+template <typename T = testing::TestCase>
+// CHECK-MESSAGES: [[@LINE-1]]:33: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: template <typename T = testing::TestSuite>
+class TestTypeHolder {};
+
+template <>
+class TestTypeHolder<testing::TestCase> {};
+// CHECK-MESSAGES: [[@LINE-1]]:31: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: class TestTypeHolder<testing::TestSuite> {};
+
+namespace shadow_using_ns {
+
+using testing::TestCase;
+// CHECK-MESSAGES: [[@LINE-1]]:16: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: using testing::TestSuite;
+
+const TestCase *testCaseUses(const TestCase &Case) {
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Google Test APIs named with 'case'
+ // CHECK-MESSAGES: [[@LINE-2]]:36: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const TestSuite *testCaseUses(const TestSuite &Case) {
+
+ // No change for implicit declarations:
+ auto Lambda = [&Case]() {};
+
+ (void)new TestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)new TestSuite();
+ const TestCase *Result = &Case;
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const TestSuite *Result = &Case;
+ return Result;
+}
+
+struct TestCaseHolder {
+ TestCase Case;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: TestSuite Case;
+};
+
+class MyTest : public TestCase {};
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: class MyTest : public TestSuite {};
+
+template <typename T = TestCase>
+// CHECK-MESSAGES: [[@LINE-1]]:24: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: template <typename T = TestSuite>
+class TestTypeHolder {};
+
+template <>
+class TestTypeHolder<TestCase> {};
+// CHECK-MESSAGES: [[@LINE-1]]:22: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: class TestTypeHolder<TestSuite> {};
+
+} // namespace shadow_using_ns
+
+const shadow_using_ns::TestCase *shadowTestCaseUses(
+ const shadow_using_ns::TestCase &Case) {
+ // CHECK-MESSAGES: [[@LINE-2]]:24: warning: Google Test APIs named with 'case'
+ // CHECK-MESSAGES: [[@LINE-2]]:28: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const shadow_using_ns::TestSuite *shadowTestCaseUses(
+ // CHECK-FIXES: const shadow_using_ns::TestSuite &Case) {
+
+ // No match for implicit declarations, as in the lambda capture:
+ auto Lambda = [&Case]() {};
+
+ (void)new shadow_using_ns::TestCase();
+ // CHECK-MESSAGES: [[@LINE-1]]:30: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: (void)new shadow_using_ns::TestSuite();
+ const shadow_using_ns::TestCase *Result = &Case;
+ // CHECK-MESSAGES: [[@LINE-1]]:26: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: const shadow_using_ns::TestSuite *Result = &Case;
+ return Result;
+}
+
+struct ShadowTestCaseHolder {
+ shadow_using_ns::TestCase Case;
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: Google Test APIs named with 'case'
+ // CHECK-FIXES: shadow_using_ns::TestSuite Case;
+};
+
+class ShadowMyTest : public shadow_using_ns::TestCase {};
+// CHECK-MESSAGES: [[@LINE-1]]:46: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: class ShadowMyTest : public shadow_using_ns::TestSuite {};
+
+template <typename T = shadow_using_ns::TestCase>
+// CHECK-MESSAGES: [[@LINE-1]]:41: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: template <typename T = shadow_using_ns::TestSuite>
+class ShadowTestTypeHolder {};
+
+template <>
+class ShadowTestTypeHolder<shadow_using_ns::TestCase> {};
+// CHECK-MESSAGES: [[@LINE-1]]:45: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: class ShadowTestTypeHolder<shadow_using_ns::TestSuite> {};
+
+namespace typedef_ns {
+
+typedef testing::TestCase MyTestCase;
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: typedef testing::TestSuite MyTestCase;
+
+const MyTestCase *testCaseUses(const MyTestCase &Case) {
+ auto Lambda = [&Case]() {};
+ (void)new MyTestCase();
+ const MyTestCase *Result = &Case;
+ return Result;
+}
+
+struct TestCaseHolder {
+ MyTestCase Case;
+};
+
+class MyTest : public MyTestCase {};
+
+template <typename T = MyTestCase>
+class TestTypeHolder {};
+
+template <>
+class TestTypeHolder<MyTestCase> {};
+
+} // namespace typedef_ns
+
+const typedef_ns::MyTestCase *typedefTestCaseUses(
+ const typedef_ns::MyTestCase &Case) {
+ auto Lambda = [&Case]() {};
+ (void)new typedef_ns::MyTestCase();
+ const typedef_ns::MyTestCase *Result = &Case;
+ return Result;
+}
+
+struct TypedefTestCaseHolder {
+ typedef_ns::MyTestCase Case;
+};
+
+class TypedefMyTest : public typedef_ns::MyTestCase {};
+template <typename T = typedef_ns::MyTestCase> class TypedefTestTypeHolder {};
+template <> class TypedefTestTypeHolder<typedef_ns::MyTestCase> {};
+
+namespace alias_ns {
+
+using MyTestCase = testing::TestCase;
+// CHECK-MESSAGES: [[@LINE-1]]:29: warning: Google Test APIs named with 'case'
+// CHECK-FIXES: using MyTestCase = testing::TestSuite;
+
+const MyTestCase *testCaseUses(const MyTestCase &Case) {
+ auto Lambda = [&Case]() {};
+ (void)new MyTestCase();
+ const MyTestCase *Result = &Case;
+ return Result;
+}
+
+struct TestCaseHolder {
+ MyTestCase Case;
+};
+
+class MyTest : public MyTestCase {};
+template <typename T = MyTestCase> class TestTypeHolder {};
+template <> class TestTypeHolder<MyTestCase> {};
+
+} // namespace alias_ns
+
+const alias_ns::MyTestCase *aliasTestCaseUses(
+ const alias_ns::MyTestCase &Case) {
+ auto Lambda = [&Case]() {};
+ (void)new alias_ns::MyTestCase();
+ const alias_ns::MyTestCase *Result = &Case;
+ return Result;
+}
+
+struct AliasTestCaseHolder {
+ alias_ns::MyTestCase Case;
+};
+
+class AliasMyTest : public alias_ns::MyTestCase {};
+template <typename T = alias_ns::MyTestCase> class AliasTestTypeHolder {};
+template <> class AliasTestTypeHolder<alias_ns::MyTestCase> {};
+
+template <typename T>
+void templateFunction(const T& t) {
+ (void)t.current_test_case();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: Google Test APIs named with 'case'
+}
+
+void instantiateTemplateFunction(const testing::UnitTest &Test) {
+ templateFunction(Test);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-exception-baseclass.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-exception-baseclass.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-exception-baseclass.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-exception-baseclass.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,284 @@
+// RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions
+
+namespace std {
+class exception {};
+class invalid_argument : public exception {};
+} // namespace std
+
+class derived_exception : public std::exception {};
+class deep_hierarchy : public derived_exception {};
+class non_derived_exception {};
+class terrible_idea : public non_derived_exception, public derived_exception {};
+
+// FIXME: More complicated kinds of inheritance should be checked later, but there is
+// currently no way use ASTMatchers for this kind of task.
+#if 0
+class bad_inheritance : private std::exception {};
+class no_good_inheritance : protected std::exception {};
+class really_creative : public non_derived_exception, private std::exception {};
+#endif
+
+void problematic() {
+ try {
+ throw int(42);
+ // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ } catch (int e) {
+ }
+ throw int(42);
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+
+ try {
+ throw 12;
+ // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ } catch (...) {
+ throw; // Ok, even if the type is not known, conforming code can never rethrow a non-std::exception object.
+ }
+
+ try {
+ throw non_derived_exception();
+ // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
+ // CHECK-NOTES: 10:1: note: type defined here
+ } catch (non_derived_exception &e) {
+ }
+ throw non_derived_exception();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
+ // CHECK-NOTES: 10:1: note: type defined here
+
+// FIXME: More complicated kinds of inheritance should be checked later, but there is
+// currently no way use ASTMatchers for this kind of task.
+#if 0
+ // Handle private inheritance cases correctly.
+ try {
+ throw bad_inheritance();
+ // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception'
+ // CHECK NOTES: 11:1: note: type defined here
+ throw no_good_inheritance();
+ // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception'
+ // CHECK NOTES: 12:1: note: type defined here
+ throw really_creative();
+ // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception'
+ // CHECK NOTES: 13:1: note: type defined here
+ } catch (...) {
+ }
+ throw bad_inheritance();
+ // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception'
+ // CHECK NOTES: 11:1: note: type defined here
+ throw no_good_inheritance();
+ // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception'
+ // CHECK NOTES: 12:1: note: type defined here
+ throw really_creative();
+ // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception'
+ // CHECK NOTES: 13:1: note: type defined here
+#endif
+}
+
+void allowed_throws() {
+ try {
+ throw std::exception(); // Ok
+ } catch (std::exception &e) { // Ok
+ }
+ throw std::exception();
+
+ try {
+ throw derived_exception(); // Ok
+ } catch (derived_exception &e) { // Ok
+ }
+ throw derived_exception(); // Ok
+
+ try {
+ throw deep_hierarchy(); // Ok, multiple levels of inheritance
+ } catch (deep_hierarchy &e) { // Ok
+ }
+ throw deep_hierarchy(); // Ok
+
+ try {
+ throw terrible_idea(); // Ok, but multiple inheritance isn't clean
+ } catch (std::exception &e) { // Can be caught as std::exception, even with multiple inheritance
+ }
+ throw terrible_idea(); // Ok, but multiple inheritance
+}
+
+void test_lambdas() {
+ auto BadLambda = []() { throw int(42); };
+ // CHECK-NOTES: [[@LINE-1]]:33: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ auto GoodLambda = []() { throw derived_exception(); };
+}
+
+// Templated function that throws exception based on template type
+template <typename T>
+void ThrowException() { throw T(); }
+// CHECK-NOTES: [[@LINE-1]]:31: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
+// CHECK-NOTES: [[@LINE-2]]:31: note: type 'bad_generic_exception<int>' is a template instantiation of 'T'
+// CHECK-NOTES: [[@LINE+25]]:1: note: type defined here
+
+// CHECK-NOTES: [[@LINE-5]]:31: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
+// CHECK-NOTES: [[@LINE-6]]:31: note: type 'bad_generic_exception<std::exception>' is a template instantiation of 'T'
+// CHECK-NOTES: [[@LINE+21]]:1: note: type defined here
+
+// CHECK-NOTES: [[@LINE-9]]:31: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
+// CHECK-NOTES: [[@LINE-10]]:31: note: type 'exotic_exception<non_derived_exception>' is a template instantiation of 'T'
+// CHECK-NOTES: [[@LINE+20]]:1: note: type defined here
+
+// CHECK-NOTES: [[@LINE-13]]:31: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+// CHECK-NOTES: [[@LINE-14]]:31: note: type 'int' is a template instantiation of 'T'
+
+// CHECK-NOTES: [[@LINE-16]]:31: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
+// CHECK-NOTES: [[@LINE-17]]:31: note: type 'non_derived_exception' is a template instantiation of 'T'
+// CHECK-NOTES: 10:1: note: type defined here
+
+#define THROW_EXCEPTION(CLASS) ThrowException<CLASS>()
+#define THROW_BAD_EXCEPTION throw int(42);
+#define THROW_GOOD_EXCEPTION throw std::exception();
+#define THROW_DERIVED_EXCEPTION throw deep_hierarchy();
+
+template <typename T>
+class generic_exception : std::exception {};
+
+template <typename T>
+class bad_generic_exception {};
+
+template <typename T>
+class exotic_exception : public T {};
+
+void generic_exceptions() {
+ THROW_EXCEPTION(int);
+ THROW_EXCEPTION(non_derived_exception);
+ THROW_EXCEPTION(std::exception); // Ok
+ THROW_EXCEPTION(derived_exception); // Ok
+ THROW_EXCEPTION(deep_hierarchy); // Ok
+
+ THROW_BAD_EXCEPTION;
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ // CHECK-NOTES: [[@LINE-22]]:35: note: expanded from macro 'THROW_BAD_EXCEPTION'
+ THROW_GOOD_EXCEPTION;
+ THROW_DERIVED_EXCEPTION;
+
+ throw generic_exception<int>(); // Ok,
+ THROW_EXCEPTION(generic_exception<float>); // Ok
+
+ throw bad_generic_exception<int>();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
+ // CHECK-NOTES: [[@LINE-24]]:1: note: type defined here
+ throw bad_generic_exception<std::exception>();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
+ // CHECK-NOTES: [[@LINE-27]]:1: note: type defined here
+ THROW_EXCEPTION(bad_generic_exception<int>);
+ THROW_EXCEPTION(bad_generic_exception<std::exception>);
+
+ throw exotic_exception<non_derived_exception>();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
+ // CHECK-NOTES: [[@LINE-30]]:1: note: type defined here
+ THROW_EXCEPTION(exotic_exception<non_derived_exception>);
+
+ throw exotic_exception<derived_exception>(); // Ok
+ THROW_EXCEPTION(exotic_exception<derived_exception>); // Ok
+}
+
+// Test for typedefed exception types
+typedef int TypedefedBad;
+typedef derived_exception TypedefedGood;
+using UsingBad = int;
+using UsingGood = deep_hierarchy;
+
+void typedefed() {
+ throw TypedefedBad();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'TypedefedBad' (aka 'int') is not derived from 'std::exception'
+ // CHECK-NOTES: [[@LINE-8]]:1: note: type defined here
+ throw TypedefedGood(); // Ok
+
+ throw UsingBad();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'UsingBad' (aka 'int') is not derived from 'std::exception'
+ // CHECK-NOTES: [[@LINE-11]]:1: note: type defined here
+ throw UsingGood(); // Ok
+}
+
+// Fix PR37913
+struct invalid_argument_maker {
+ ::std::invalid_argument operator()() const;
+};
+struct int_maker {
+ int operator()() const;
+};
+
+template <typename T>
+void templated_thrower() {
+ throw T{}();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+}
+template <typename T>
+void templated_thrower2() {
+ T ExceptionFactory; // This test found a <dependant-type> which did not happend with 'throw T{}()'
+ throw ExceptionFactory();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+}
+
+void exception_created_with_function() {
+ templated_thrower<invalid_argument_maker>();
+ templated_thrower<int_maker>();
+
+ templated_thrower2<invalid_argument_maker>();
+ templated_thrower2<int_maker>();
+
+ throw invalid_argument_maker{}();
+ throw int_maker{}();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+}
+
+struct invalid_argument_factory {
+ ::std::invalid_argument make_exception() const;
+};
+
+struct int_factory {
+ int make_exception() const;
+};
+
+template <typename T>
+void templated_factory() {
+ T f;
+ throw f.make_exception();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+}
+template <typename T>
+void templated_factory2() {
+ throw T().make_exception();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+}
+
+void exception_from_factory() {
+ templated_factory<invalid_argument_factory>();
+ templated_factory<int_factory>();
+
+ templated_factory2<invalid_argument_factory>();
+ templated_factory2<int_factory>();
+
+ throw invalid_argument_factory().make_exception();
+ throw int_factory().make_exception();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+
+ invalid_argument_factory inv_f;
+ throw inv_f.make_exception();
+
+ int_factory int_f;
+ throw int_f.make_exception();
+ // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+}
+
+template <typename T>
+struct ThrowClassTemplateParam {
+ ThrowClassTemplateParam() { throw T(); }
+ // CHECK-NOTES: [[@LINE-1]]:37: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ // CHECK-NOTES: [[@LINE-2]]:37: note: type 'int' is a template instantiation of 'T'
+};
+
+template <int V>
+struct ThrowValueTemplate {
+ ThrowValueTemplate() { throw V; }
+ // CHECK-NOTES: [[@LINE-1]]:32: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+};
+
+void class_templates() {
+ ThrowClassTemplateParam<int> IntThrow;
+ ThrowClassTemplateParam<std::invalid_argument> ArgThrow;
+
+ ThrowValueTemplate<42> ValueThrow;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered-else.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered-else.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered-else.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered-else.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s hicpp-multiway-paths-covered %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: hicpp-multiway-paths-covered.WarnOnMissingElse, value: 1}]}'\
+// RUN: --
+
+enum OS { Mac,
+ Windows,
+ Linux };
+
+void problematic_if(int i, enum OS os) {
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: potentially uncovered codepath; add an ending else statement
+ return;
+ }
+
+ // Could be considered as false positive because all paths are covered logically.
+ // I still think this is valid since the possibility of a final 'everything else'
+ // codepath is expected from if-else if.
+ if (i > 0) {
+ return;
+ } else if (i <= 0) {
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: potentially uncovered codepath; add an ending else statement
+ return;
+ }
+
+ // Test if nesting of if-else chains does get caught as well.
+ if (os == Mac) {
+ return;
+ } else if (os == Linux) {
+ // These checks are kind of degenerated, but the check will not try to solve
+ // if logically all paths are covered, which is more the area of the static analyzer.
+ if (true) {
+ return;
+ } else if (false) {
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: potentially uncovered codepath; add an ending else statement
+ return;
+ }
+ return;
+ } else {
+ /* unreachable */
+ if (true) // check if the parent would match here as well
+ return;
+ // No warning for simple if statements, since it is common to just test one condition
+ // and ignore the opposite.
+ }
+
+ // Ok, because all paths are covered
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ return;
+ } else {
+ /* error, maybe precondition failed */
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-multiway-paths-covered.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,468 @@
+// RUN: %check_clang_tidy %s hicpp-multiway-paths-covered %t
+
+enum OS { Mac,
+ Windows,
+ Linux };
+
+struct Bitfields {
+ unsigned UInt : 3;
+ int SInt : 1;
+};
+
+int return_integer() { return 42; }
+
+void bad_switch(int i) {
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch with only one case; use an if statement
+ case 0:
+ break;
+ }
+ // No default in this switch
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ break;
+ case 1:
+ break;
+ case 2:
+ break;
+ }
+
+ // degenerate, maybe even warning
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch statement without labels has no effect
+ }
+
+ switch (int j = return_integer()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ case 2:
+ break;
+ }
+
+ // Degenerated, only default case.
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: degenerated switch with default label only
+ default:
+ break;
+ }
+
+ // Degenerated, only one case label and default case -> Better as if-stmt.
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch could be better written as an if/else statement
+ case 0:
+ break;
+ default:
+ break;
+ }
+
+ unsigned long long BigNumber = 0;
+ switch (BigNumber) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ break;
+ }
+
+ const int &IntRef = i;
+ switch (IntRef) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ break;
+ }
+
+ char C = 'A';
+ switch (C) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 'A':
+ break;
+ case 'B':
+ break;
+ }
+
+ Bitfields Bf;
+ // UInt has 3 bits size.
+ switch (Bf.UInt) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ break;
+ }
+ // All paths explicitly covered.
+ switch (Bf.UInt) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ break;
+ }
+ // SInt has 1 bit size, so this is somewhat degenerated.
+ switch (Bf.SInt) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch with only one case; use an if statement
+ case 0:
+ break;
+ }
+ // All paths explicitly covered.
+ switch (Bf.SInt) {
+ case 0:
+ case 1:
+ break;
+ }
+
+ bool Flag = false;
+ switch (Flag) {
+ // CHECK-MESSAGES:[[@LINE-1]]:3: warning: switch with only one case; use an if statement
+ case true:
+ break;
+ }
+
+ switch (Flag) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: degenerated switch with default label only
+ default:
+ break;
+ }
+
+ // This `switch` will create a frontend warning from '-Wswitch-bool' but is
+ // ok for this check.
+ switch (Flag) {
+ case true:
+ break;
+ case false:
+ break;
+ }
+}
+
+void unproblematic_switch(unsigned char c) {
+ //
+ switch (c) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 59:
+ case 60:
+ case 61:
+ case 62:
+ case 63:
+ case 64:
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ case 73:
+ case 74:
+ case 75:
+ case 76:
+ case 77:
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ case 85:
+ case 86:
+ case 87:
+ case 88:
+ case 89:
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ case 108:
+ case 109:
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ case 114:
+ case 115:
+ case 116:
+ case 117:
+ case 118:
+ case 119:
+ case 120:
+ case 121:
+ case 122:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ case 127:
+ case 128:
+ case 129:
+ case 130:
+ case 131:
+ case 132:
+ case 133:
+ case 134:
+ case 135:
+ case 136:
+ case 137:
+ case 138:
+ case 139:
+ case 140:
+ case 141:
+ case 142:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ case 147:
+ case 148:
+ case 149:
+ case 150:
+ case 151:
+ case 152:
+ case 153:
+ case 154:
+ case 155:
+ case 156:
+ case 157:
+ case 158:
+ case 159:
+ case 160:
+ case 161:
+ case 162:
+ case 163:
+ case 164:
+ case 165:
+ case 166:
+ case 167:
+ case 168:
+ case 169:
+ case 170:
+ case 171:
+ case 172:
+ case 173:
+ case 174:
+ case 175:
+ case 176:
+ case 177:
+ case 178:
+ case 179:
+ case 180:
+ case 181:
+ case 182:
+ case 183:
+ case 184:
+ case 185:
+ case 186:
+ case 187:
+ case 188:
+ case 189:
+ case 190:
+ case 191:
+ case 192:
+ case 193:
+ case 194:
+ case 195:
+ case 196:
+ case 197:
+ case 198:
+ case 199:
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ case 204:
+ case 205:
+ case 206:
+ case 207:
+ case 208:
+ case 209:
+ case 210:
+ case 211:
+ case 212:
+ case 213:
+ case 214:
+ case 215:
+ case 216:
+ case 217:
+ case 218:
+ case 219:
+ case 220:
+ case 221:
+ case 222:
+ case 223:
+ case 224:
+ case 225:
+ case 226:
+ case 227:
+ case 228:
+ case 229:
+ case 230:
+ case 231:
+ case 232:
+ case 233:
+ case 234:
+ case 235:
+ case 236:
+ case 237:
+ case 238:
+ case 239:
+ case 240:
+ case 241:
+ case 242:
+ case 243:
+ case 244:
+ case 245:
+ case 246:
+ case 247:
+ case 248:
+ case 249:
+ case 250:
+ case 251:
+ case 252:
+ case 253:
+ case 254:
+ case 255:
+ break;
+ }
+
+ // Some paths are covered by the switch and a default case is present.
+ switch (c) {
+ case 1:
+ case 2:
+ case 3:
+ default:
+ break;
+ }
+}
+
+OS return_enumerator() {
+ return Linux;
+}
+
+// Enumpaths are already covered by a warning, this is just to ensure, that there is
+// no interference or false positives.
+// -Wswitch warns about uncovered enum paths and each here described case is already
+// covered.
+void switch_enums(OS os) {
+ switch (os) {
+ case Linux:
+ break;
+ }
+
+ switch (OS another_os = return_enumerator()) {
+ case Linux:
+ break;
+ }
+
+ switch (os) {
+ }
+}
+
+/// All of these cases will not emit a warning per default, but with explicit activation.
+/// Covered in extra test file.
+void problematic_if(int i, enum OS os) {
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ return;
+ }
+
+ if (os == Mac) {
+ return;
+ } else if (os == Linux) {
+ if (true) {
+ return;
+ } else if (false) {
+ return;
+ }
+ return;
+ } else {
+ /* unreachable */
+ if (true) // check if the parent would match here as well
+ return;
+ }
+
+ // Ok, because all paths are covered
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ return;
+ } else {
+ /* error, maybe precondition failed */
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler-msvc.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler-msvc.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler-msvc.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler-msvc.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,11 @@
+// REQUIRES: system-windows
+// FIXME: Re-enable test on windows (PR36855)
+// UNSUPPORTED: system-windows
+// RUN: %check_clang_tidy %s hicpp-no-assembler %t
+
+void f() {
+ _asm {
+ mov al, 2;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-no-assembler.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy %s hicpp-no-assembler %t
+
+__asm__(".symver foo, bar at v");
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+
+static int s asm("spam");
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+
+void f() {
+ __asm("mov al, 2");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-bug34747.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-bug34747.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-bug34747.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-bug34747.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,29 @@
+// RUN: %check_clang_tidy %s hicpp-signed-bitwise %t --
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+template <typename C>
+struct OutputStream {
+ OutputStream &operator<<(C);
+};
+
+template <typename C>
+struct foo {
+ typedef OutputStream<C> stream_type;
+ foo(stream_type &o) {
+ o << 'x'; // warning occured here, fixed now
+ }
+};
+
+void bar(OutputStream<signed char> &o) {
+ foo<signed char> f(o);
+}
+
+void silence_lit() {
+ int SValue = 42;
+ int SResult;
+
+ SResult = SValue & 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,198 @@
+// RUN: clang-tidy %s -checks='-*,hicpp-signed-bitwise' -- -std=c++11
+// FIXME: Make the test work in all language modes.
+
+#include "hicpp-signed-bitwise-standard-types.h"
+
+void pure_bitmask_types() {
+ // std::locale::category
+ int SResult = 0;
+ std::locale::category C = std::locale::category::ctype;
+
+ SResult = std::locale::category::none | std::locale::category::collate;
+ SResult|= std::locale::category::collate;
+ SResult = std::locale::category::ctype & std::locale::category::monetary;
+ SResult&= std::locale::category::monetary;
+ SResult = std::locale::category::numeric ^ std::locale::category::time;
+ SResult^= std::locale::category::time;
+ SResult = std::locale::category::messages | std::locale::category::all;
+
+ SResult = std::locale::category::all & C;
+ SResult&= std::locale::category::all;
+ SResult = std::locale::category::all | C;
+ SResult|= std::locale::category::all;
+ SResult = std::locale::category::all ^ C;
+ SResult^= std::locale::category::all;
+
+ // std::ctype_base::mask
+ std::ctype_base::mask M = std::ctype_base::mask::punct;
+
+ SResult = std::ctype_base::mask::space | std::ctype_base::mask::print;
+ SResult = std::ctype_base::mask::cntrl & std::ctype_base::mask::upper;
+ SResult = std::ctype_base::mask::lower ^ std::ctype_base::mask::alpha;
+ SResult|= std::ctype_base::mask::digit | std::ctype_base::mask::punct;
+ SResult&= std::ctype_base::mask::xdigit & std::ctype_base::mask::alnum;
+ SResult^= std::ctype_base::mask::alnum ^ std::ctype_base::mask::graph;
+
+ SResult&= std::ctype_base::mask::space & M;
+ SResult|= std::ctype_base::mask::space | M;
+ SResult^= std::ctype_base::mask::space ^ M;
+
+ // std::ios_base::fmtflags
+ std::ios_base::fmtflags F = std::ios_base::fmtflags::floatfield;
+
+ SResult = std::ios_base::fmtflags::dec | std::ios_base::fmtflags::oct;
+ SResult = std::ios_base::fmtflags::hex & std::ios_base::fmtflags::basefield;
+ SResult = std::ios_base::fmtflags::left ^ std::ios_base::fmtflags::right;
+ SResult|= std::ios_base::fmtflags::internal | std::ios_base::fmtflags::adjustfield;
+ SResult&= std::ios_base::fmtflags::scientific & std::ios_base::fmtflags::fixed;
+ SResult^= std::ios_base::fmtflags::floatfield ^ std::ios_base::fmtflags::boolalpha;
+ SResult = std::ios_base::fmtflags::showbase | std::ios_base::fmtflags::showpoint;
+ SResult = std::ios_base::fmtflags::showpos & std::ios_base::fmtflags::skipws;
+ SResult = std::ios_base::fmtflags::unitbuf ^ std::ios_base::fmtflags::uppercase;
+
+ SResult|= std::ios_base::fmtflags::unitbuf | F;
+ SResult&= std::ios_base::fmtflags::unitbuf & F;
+ SResult^= std::ios_base::fmtflags::unitbuf ^ F;
+
+ // std::ios_base::iostate
+ std::ios_base::iostate S = std::ios_base::iostate::goodbit;
+
+ SResult^= std::ios_base::iostate::goodbit | std::ios_base::iostate::badbit;
+ SResult|= std::ios_base::iostate::failbit & std::ios_base::iostate::eofbit;
+ SResult&= std::ios_base::iostate::failbit ^ std::ios_base::iostate::eofbit;
+
+ SResult = std::ios_base::iostate::goodbit | S;
+ SResult = std::ios_base::iostate::goodbit & S;
+ SResult = std::ios_base::iostate::goodbit ^ S;
+
+ // std::ios_base::openmode
+ std::ios_base::openmode B = std::ios_base::openmode::binary;
+
+ SResult = std::ios_base::openmode::app | std::ios_base::openmode::binary;
+ SResult = std::ios_base::openmode::in & std::ios_base::openmode::out;
+ SResult = std::ios_base::openmode::trunc ^ std::ios_base::openmode::ate;
+
+ SResult&= std::ios_base::openmode::trunc | B;
+ SResult^= std::ios_base::openmode::trunc & B;
+ SResult|= std::ios_base::openmode::trunc ^ B;
+}
+
+void still_forbidden() {
+ // std::locale::category
+ unsigned int UResult = 0u;
+ int SResult = 0;
+
+ SResult = std::ctype_base::mask::print ^ 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = std::ctype_base::mask::cntrl | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = std::ctype_base::mask::upper & 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = std::ctype_base::mask::lower ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ // Staying within the allowed standard types is ok for bitwise assignment
+ // operations.
+ std::ctype_base::mask var = std::ctype_base::mask::print;
+ SResult<<= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult>>= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult &= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult |= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult ^= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::locale::category::collate << 1u;
+ UResult = std::locale::category::ctype << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::locale::category::monetary >> 1u;
+ UResult = std::locale::category::numeric >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = ~std::locale::category::messages;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::locale::category::all;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ctype_base::mask
+ UResult = std::ctype_base::mask::space | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ctype_base::mask::print & 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ctype_base::mask::cntrl ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ctype_base::mask::upper << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ctype_base::mask::lower << 1u;
+ UResult = std::ctype_base::mask::alpha >> 1u;
+ UResult = std::ctype_base::mask::digit >> 1u;
+
+ UResult = ~std::ctype_base::mask::punct;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ctype_base::mask::xdigit;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ios_base::fmtflags
+ UResult = std::ios_base::fmtflags::dec | 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::oct & 1u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::hex ^ -1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ios_base::fmtflags::basefield >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::left >> 1u;
+ UResult = std::ios_base::fmtflags::right << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::internal << 1u;
+
+ UResult = ~std::ios_base::fmtflags::adjustfield;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ios_base::fmtflags::scientific;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ios_base::iostate
+ UResult = std::ios_base::iostate::goodbit | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::badbit & 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::failbit ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ios_base::iostate::eofbit << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::goodbit << 1u;
+ UResult = std::ios_base::iostate::badbit >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::failbit >> 1u;
+
+ UResult = ~std::ios_base::iostate::eofbit;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ios_base::iostate::goodbit;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ios_base::openmode
+ UResult = std::ios_base::app | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::binary & 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::in ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ios_base::out >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::trunc >> 1u;
+ UResult = std::ios_base::ate << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::ate << 1u;
+
+ UResult = ~std::ios_base::openmode::app;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ios_base::openmode::binary;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.h?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.h (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise-standard-types.h Fri Oct 11 05:05:42 2019
@@ -0,0 +1,81 @@
+#pragma clang system_header
+
+// Implement standard types that are known to be defined as unsigned in some
+// implementations like MSVC.
+namespace std {
+namespace locale {
+enum category : int {
+ none = 0u,
+ collate = 1u << 1u,
+ ctype = 1u << 2u,
+ monetary = 1u << 3u,
+ numeric = 1u << 4u,
+ time = 1u << 5u,
+ messages = 1u << 6u,
+ all = none | collate | ctype | monetary | numeric | time | messages
+ // CHECK MESSAGES: [[@LINE-1]]:9: warning: use of a signed integer operand with a binary bitwise operator
+};
+} // namespace locale
+
+namespace ctype_base {
+enum mask : int {
+ space,
+ print,
+ cntrl,
+ upper,
+ lower,
+ alpha,
+ digit,
+ punct,
+ xdigit,
+ /* blank, // C++11 */
+ alnum = alpha | digit,
+ // CHECK MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ graph = alnum | punct
+ // CHECK MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+};
+} // namespace ctype_base
+
+namespace ios_base {
+enum fmtflags : int {
+ dec = 0u,
+ oct = 1u << 2u,
+ hex = 1u << 3u,
+ basefield = dec | oct | hex | 0u,
+ // CHECK MESSAGES: [[@LINE-1]]:15: warning: use of a signed integer operand with a binary bitwise operator
+ left = 1u << 4u,
+ right = 1u << 5u,
+ internal = 1u << 6u,
+ adjustfield = left | right | internal,
+ // CHECK MESSAGES: [[@LINE-1]]:17: warning: use of a signed integer operand with a binary bitwise operator
+ scientific = 1u << 7u,
+ fixed = 1u << 8u,
+ floatfield = scientific | fixed | (scientific | fixed) | 0u,
+ // CHECK MESSAGES: [[@LINE-1]]:16: warning: use of a signed integer operand with a binary bitwise operator
+ // CHECK MESSAGES: [[@LINE-2]]:38: warning: use of a signed integer operand with a binary bitwise operator
+ boolalpha = 1u << 9u,
+ showbase = 1u << 10u,
+ showpoint = 1u << 11u,
+ showpos = 1u << 12u,
+ skipws = 1u << 13u,
+ unitbuf = 1u << 14u,
+ uppercase = 1u << 15u
+};
+
+enum iostate : int {
+ goodbit = 0u,
+ badbit = 1u << 1u,
+ failbit = 1u << 2u,
+ eofbit = 1u << 3u
+};
+
+enum openmode : int {
+ app = 0u,
+ binary = 0u << 1u,
+ in = 0u << 2u,
+ out = 0u << 3u,
+ trunc = 0u << 4u,
+ ate = 0u << 5u
+};
+} // namespace ios_base
+} // namespace std
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/hicpp-signed-bitwise.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,240 @@
+// RUN: %check_clang_tidy %s hicpp-signed-bitwise %t -- -- --target=x86_64-linux
+
+// These could cause false positives and should not be considered.
+struct StreamClass {
+};
+StreamClass &operator<<(StreamClass &os, unsigned int i) {
+ return os;
+}
+StreamClass &operator<<(StreamClass &os, int i) {
+ return os;
+}
+StreamClass &operator>>(StreamClass &os, unsigned int i) {
+ return os;
+}
+StreamClass &operator>>(StreamClass &os, int i) {
+ return os;
+}
+struct AnotherStream {
+ AnotherStream &operator<<(unsigned char c) { return *this; }
+ AnotherStream &operator<<(signed char c) { return *this; }
+
+ AnotherStream &operator>>(unsigned char c) { return *this; }
+ AnotherStream &operator>>(signed char c) { return *this; }
+};
+
+void binary_bitwise() {
+ int SValue = 42;
+ int SResult;
+
+ unsigned int UValue = 42;
+ unsigned int UResult;
+
+ SResult = SValue & 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = SValue & -1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = SValue & SValue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = SValue & 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = SValue & -1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult&= 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = UValue & 1u; // Ok
+ UResult = UValue & UValue; // Ok
+ UResult&= 2u; // Ok
+
+ unsigned char UByte1 = 0u;
+ unsigned char UByte2 = 16u;
+ signed char SByte1 = 0;
+ signed char SByte2 = 16;
+
+ UByte1 = UByte1 & UByte2; // Ok
+ UByte1 = SByte1 & UByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1 = SByte1 & SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ SByte1 = SByte1 & SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+
+ // More complex expressions.
+ UResult = UValue & (SByte1 + (SByte1 | SByte2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: use of a signed integer operand with a binary bitwise operator
+
+ // The rest is to demonstrate functionality but all operators are matched equally.
+ // Therefore functionality is the same for all binary operations.
+ UByte1 = UByte1 | UByte2; // Ok
+ UByte1 = UByte1 | SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1|= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1|= UByte2; // Ok
+
+ UByte1 = UByte1 ^ UByte2; // Ok
+ UByte1 = UByte1 ^ SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1^= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1^= UByte2; // Ok
+
+ UByte1 = UByte1 >> UByte2; // Ok
+ UByte1 = UByte1 >> SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1>>= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1>>= UByte2; // Ok
+
+ UByte1 = UByte1 << UByte2; // Ok
+ UByte1 = UByte1 << SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1<<= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1<<= UByte2; // Ok
+
+ int SignedInt1 = 1 << 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use of a signed integer operand with a binary bitwise operator
+ int SignedInt2 = 1u << 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use of a signed integer operand with a binary bitwise operator
+}
+
+void f1(unsigned char c) {}
+void f2(signed char c) {}
+void f3(int c) {}
+
+void unary_bitwise() {
+ unsigned char UByte1 = 0u;
+ signed char SByte1 = 0;
+
+ UByte1 = ~UByte1; // Ok
+ SByte1 = ~UByte1;
+ SByte1 = ~SByte1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a unary bitwise operator
+ UByte1 = ~SByte1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a unary bitwise operator
+
+ unsigned int UInt = 0u;
+ int SInt = 0;
+
+ f1(~UByte1); // Ok
+ f1(~SByte1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f1(~UInt);
+ f1(~SInt);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f2(~UByte1);
+ f2(~SByte1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f2(~UInt);
+ f2(~SInt);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f3(~UByte1); // Ok
+ f3(~SByte1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+}
+
+/// HICPP uses these examples to demonstrate the rule.
+void standard_examples() {
+ int i = 3;
+ unsigned int k = 0u;
+
+ int r = i << -1; // Emits -Wshift-count-negative from clang
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ r = i << 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+
+ r = -1 >> -1; // Emits -Wshift-count-negative from clang
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+ r = -1 >> 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+
+ r = -1 >> i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+ r = -1 >> -i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+
+ r = ~0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a unary bitwise operator
+ r = ~0u; // Ok
+ k = ~k; // Ok
+
+ unsigned int u = (-1) & 2u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use of a signed integer operand with a binary bitwise operator
+ u = (-1) | 1u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+ u = (-1) ^ 1u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+}
+
+void streams_should_work() {
+ StreamClass s;
+ s << 1u; // Ok
+ s << 1; // Ok
+ s >> 1; // Ok
+ s >> 1u; // Ok
+
+ AnotherStream as;
+ unsigned char uc = 1u;
+ signed char sc = 1;
+ as << uc; // Ok
+ as << sc; // Ok
+ as >> uc; // Ok
+ as >> sc; // Ok
+}
+
+enum OldEnum {
+ ValueOne,
+ ValueTwo,
+};
+
+enum OldSigned : int {
+ IntOne,
+ IntTwo,
+};
+
+void classicEnums() {
+ OldEnum e1 = ValueOne, e2 = ValueTwo;
+ int e3; // Using the enum type, results in an error.
+ e3 = ValueOne | ValueTwo; // Ok
+ e3 = ValueOne & ValueTwo; // Ok
+ e3 = ValueOne ^ ValueTwo; // Ok
+ e3 = e1 | e2; // Ok
+ e3 = e1 & e2; // Ok
+ e3 = e1 ^ e2; // Ok
+
+ OldSigned s1 = IntOne, s2 = IntTwo;
+ int s3;
+ s3 = IntOne | IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3|= IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = IntOne & IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3&= IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = IntOne ^ IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3^= IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = s1 | s2; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = s1 & s2; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = s1 ^ s2; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+}
+
+enum EnumConstruction {
+ one = 1,
+ two = 2,
+ test1 = 1 << 12,
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ test2 = one << two,
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ test3 = 1u << 12,
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/linuxkernel-must-check-errs.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/linuxkernel-must-check-errs.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/linuxkernel-must-check-errs.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/linuxkernel-must-check-errs.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,43 @@
+// RUN: %check_clang_tidy %s linuxkernel-must-check-errs %t
+
+#define __must_check __attribute__((warn_unused_result))
+
+// Prototypes of the error functions.
+void * __must_check ERR_PTR(long error);
+long __must_check PTR_ERR(const void *ptr);
+int __must_check IS_ERR(const void *ptr);
+int __must_check IS_ERR_OR_NULL(const void *ptr);
+void * __must_check ERR_CAST(const void *ptr);
+int __must_check PTR_ERR_OR_ZERO(const void *ptr);
+
+void f() {
+ ERR_PTR(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'ERR_PTR' is unused
+ PTR_ERR((void *)0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'PTR_ERR' is unused
+ IS_ERR((void *)0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'IS_ERR' is unused
+ ERR_CAST((void *)0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'ERR_CAST' is unused
+out:
+ PTR_ERR_OR_ZERO((void *)0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'PTR_ERR_OR_ZERO' is unused
+}
+
+void *f1() {
+ return ERR_PTR(0);
+}
+
+long f2() {
+ if (IS_ERR((void *)0)) {
+ return PTR_ERR((void *)0);
+ }
+ return -1;
+}
+
+void f3() {
+ f1();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'f1' is unused but represents an error value
+ f2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'f2' is unused but represents an error value
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-include-order.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-include-order.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-include-order.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-include-order.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s llvm-include-order %t -- -- -isystem %S/Inputs/Headers
+
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: #includes are not sorted properly
+#include "j.h"
+#include "gtest/foo.h"
+#include "i.h"
+#include <s.h>
+#include "llvm/a.h"
+#include "clang/b.h"
+#include "clang-c/c.h" // hi
+#include "llvm-c/d.h" // -c
+
+// CHECK-FIXES: #include "j.h"
+// CHECK-FIXES-NEXT: #include "i.h"
+// CHECK-FIXES-NEXT: #include "clang-c/c.h" // hi
+// CHECK-FIXES-NEXT: #include "clang/b.h"
+// CHECK-FIXES-NEXT: #include "llvm-c/d.h" // -c
+// CHECK-FIXES-NEXT: #include "llvm/a.h"
+// CHECK-FIXES-NEXT: #include "gtest/foo.h"
+// CHECK-FIXES-NEXT: #include <s.h>
+
+#include "b.h"
+#ifdef FOO
+#include "a.h"
+#endif
+
+// CHECK-FIXES: #include "b.h"
+// CHECK-FIXES-NEXT: #ifdef FOO
+// CHECK-FIXES-NEXT: #include "a.h"
+// CHECK-FIXES-NEXT: #endif
+
+// CHECK-MESSAGES: [[@LINE+1]]:1: warning: #includes are not sorted properly
+#include "b.h"
+#include "a.h"
+
+// CHECK-FIXES: #include "a.h"
+// CHECK-FIXES-NEXT: #include "b.h"
+
+// CHECK-MESSAGES-NOT: [[@LINE+1]]:1: warning: #includes are not sorted properly
+#include "cross-file-c.h"
+// This line number should correspond to the position of the #include in cross-file-c.h
+#include "cross-file-a.h"
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-isa-or-dyn-cast-in-conditionals.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-isa-or-dyn-cast-in-conditionals.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-isa-or-dyn-cast-in-conditionals.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-isa-or-dyn-cast-in-conditionals.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,132 @@
+// RUN: %check_clang_tidy %s llvm-prefer-isa-or-dyn-cast-in-conditionals %t
+
+struct X;
+struct Y;
+struct Z {
+ int foo();
+ X *bar();
+ X *cast(Y*);
+ bool baz(Y*);
+};
+
+template <class X, class Y>
+bool isa(Y *);
+template <class X, class Y>
+X *cast(Y *);
+template <class X, class Y>
+X *dyn_cast(Y *);
+template <class X, class Y>
+X *dyn_cast_or_null(Y *);
+
+bool foo(Y *y, Z *z) {
+ if (auto x = cast<X>(y))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: cast<> in conditional will assert rather than return a null pointer [llvm-prefer-isa-or-dyn-cast-in-conditionals]
+ // CHECK-FIXES: if (auto x = dyn_cast<X>(y))
+
+ while (auto x = cast<X>(y))
+ break;
+ // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: cast<> in conditional
+ // CHECK-FIXES: while (auto x = dyn_cast<X>(y))
+
+ if (cast<X>(y))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: cast<> in conditional
+ // CHECK-FIXES: if (isa<X>(y))
+
+ while (cast<X>(y))
+ break;
+ // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: cast<> in conditional
+ // CHECK-FIXES: while (isa<X>(y))
+
+ do {
+ break;
+ } while (cast<X>(y));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: cast<> in conditional
+ // CHECK-FIXES: while (isa<X>(y));
+
+ if (dyn_cast<X>(y))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: return value from dyn_cast<> not used [llvm-prefer-isa-or-dyn-cast-in-conditionals]
+ // CHECK-FIXES: if (isa<X>(y))
+
+ while (dyn_cast<X>(y))
+ break;
+ // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: return value from dyn_cast<> not used
+ // CHECK-FIXES: while (isa<X>(y))
+
+ do {
+ break;
+ } while (dyn_cast<X>(y));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return value from dyn_cast<> not used
+ // CHECK-FIXES: while (isa<X>(y));
+
+ if (y && isa<X>(y))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: isa_and_nonnull<> is preferred over an explicit test for null followed by calling isa<> [llvm-prefer-isa-or-dyn-cast-in-conditionals]
+ // CHECK-FIXES: if (isa_and_nonnull<X>(y))
+
+ if (z->bar() && isa<Y>(z->bar()))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: isa_and_nonnull<> is preferred
+ // CHECK-FIXES: if (isa_and_nonnull<Y>(z->bar()))
+
+ if (z->bar() && cast<Y>(z->bar()))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: isa_and_nonnull<> is preferred
+ // CHECK-FIXES: if (isa_and_nonnull<Y>(z->bar()))
+
+ if (z->bar() && dyn_cast<Y>(z->bar()))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: isa_and_nonnull<> is preferred
+ // CHECK-FIXES: if (isa_and_nonnull<Y>(z->bar()))
+
+ if (z->bar() && dyn_cast_or_null<Y>(z->bar()))
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: isa_and_nonnull<> is preferred
+ // CHECK-FIXES: if (isa_and_nonnull<Y>(z->bar()))
+
+ bool b = z->bar() && cast<Y>(z->bar());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: isa_and_nonnull<> is preferred
+ // CHECK-FIXES: bool b = isa_and_nonnull<Y>(z->bar());
+
+ // These don't trigger a warning.
+ if (auto x = cast<Z>(y)->foo())
+ return true;
+ if (auto x = z->cast(y))
+ return true;
+ while (auto x = cast<Z>(y)->foo())
+ break;
+ if (cast<Z>(y)->foo())
+ return true;
+ if (z->cast(y))
+ return true;
+ while (cast<Z>(y)->foo())
+ break;
+ if (y && cast<X>(z->bar()))
+ return true;
+ if (z && cast<Z>(y)->foo())
+ return true;
+ bool b2 = y && cast<X>(z);
+ if(z->cast(y))
+ return true;
+ if (z->baz(cast<Y>(z)))
+ return true;
+
+#define CAST(T, Obj) cast<T>(Obj)
+#define AUTO_VAR_CAST(X, Y, Z) auto X = cast<Y>(Z)
+#define ISA(T, Obj) isa<T>(Obj)
+#define ISA_OR_NULL(T, Obj) Obj &&isa<T>(Obj)
+
+ // Macros don't trigger warning.
+ if (auto x = CAST(X, y))
+ return true;
+ if (AUTO_VAR_CAST(x, X, z))
+ return true;
+ if (z->bar() && ISA(Y, z->bar()))
+ return true;
+ if (ISA_OR_NULL(Y, z->bar()))
+ return true;
+
+ return false;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,143 @@
+// RUN: %check_clang_tidy %s llvm-prefer-register-over-unsigned %t
+
+namespace llvm {
+class Register {
+public:
+ operator unsigned();
+
+ unsigned Reg;
+};
+
+// This class shouldn't trigger it despite the similarity.
+class RegisterLike {
+public:
+ operator unsigned();
+
+ unsigned Reg;
+};
+} // end namespace llvm
+
+llvm::Register getReg();
+llvm::RegisterLike getRegLike();
+
+void apply_1() {
+ unsigned Reg1 = getReg();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: variable 'Reg1' declared as 'unsigned int'; use 'llvm::Register' instead [llvm-prefer-register-over-unsigned]
+ // CHECK-FIXES: apply_1()
+ // CHECK-FIXES-NEXT: llvm::Register Reg1 = getReg();
+}
+
+void apply_2() {
+ using namespace llvm;
+ unsigned Reg2 = getReg();
+ // FIXME: Function-scoped UsingDirectiveDecl's don't appear to be in the
+ // DeclContext for the function so we can't elide the llvm:: in this
+ // case. Fortunately, it doesn't actually occur in the LLVM code base.
+ // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: variable 'Reg2' declared as 'unsigned int'; use 'llvm::Register' instead [llvm-prefer-register-over-unsigned]
+ // CHECK-FIXES: apply_2()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: llvm::Register Reg2 = getReg();
+}
+
+namespace llvm {
+void apply_3() {
+ unsigned Reg3 = getReg();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: variable 'Reg3' declared as 'unsigned int'; use 'Register' instead [llvm-prefer-register-over-unsigned]
+ // CHECK-FIXES: apply_3()
+ // CHECK-FIXES-NEXT: Register Reg3 = getReg();
+}
+} // end namespace llvm
+
+void done_1() {
+ llvm::Register Reg1 = getReg();
+ // CHECK-FIXES: done_1()
+ // CHECK-FIXES-NEXT: llvm::Register Reg1 = getReg();
+}
+
+void done_2() {
+ using namespace llvm;
+ Register Reg2 = getReg();
+ // CHECK-FIXES: done_2()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: Register Reg2 = getReg();
+}
+
+namespace llvm {
+void done_3() {
+ Register Reg3 = getReg();
+ // CHECK-FIXES: done_3()
+ // CHECK-FIXES-NEXT: Register Reg3 = getReg();
+}
+} // end namespace llvm
+
+void do_nothing_1() {
+ unsigned Reg1 = getRegLike();
+ // CHECK-FIXES: do_nothing_1()
+ // CHECK-FIXES-NEXT: unsigned Reg1 = getRegLike();
+}
+
+void do_nothing_2() {
+ using namespace llvm;
+ unsigned Reg2 = getRegLike();
+ // CHECK-FIXES: do_nothing_2()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: unsigned Reg2 = getRegLike();
+}
+
+namespace llvm {
+void do_nothing_3() {
+ unsigned Reg3 = getRegLike();
+ // CHECK-FIXES: do_nothing_3()
+ // CHECK-FIXES-NEXT: unsigned Reg3 = getRegLike();
+}
+} // end namespace llvm
+
+void fn1(llvm::Register R);
+void do_nothing_4() {
+ fn1(getReg());
+ // CHECK-FIXES: do_nothing_4()
+ // CHECK-FIXES-NEXT: fn1(getReg());
+}
+
+void fn2(unsigned R);
+void do_nothing_5() {
+ fn2(getReg());
+ // CHECK-FIXES: do_nothing_5()
+ // CHECK-FIXES-NEXT: fn2(getReg());
+}
+
+void do_nothing_6() {
+ using namespace llvm;
+ Register Reg6{getReg()};
+ // CHECK-FIXES: do_nothing_6()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: Register Reg6{getReg()};
+}
+
+void do_nothing_7() {
+ using namespace llvm;
+ Register Reg7;
+ Reg7.Reg = getReg();
+ // CHECK-FIXES: do_nothing_7()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: Register Reg7;
+ // CHECK-FIXES-NEXT: Reg7.Reg = getReg();
+}
+
+void do_nothing_8() {
+ using namespace llvm;
+ RegisterLike Reg8{getReg()};
+ // CHECK-FIXES: do_nothing_8()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: RegisterLike Reg8{getReg()};
+}
+
+void do_nothing_9() {
+ using namespace llvm;
+ RegisterLike Reg9;
+ Reg9.Reg = getReg();
+ // CHECK-FIXES: do_nothing_9()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: RegisterLike Reg9;
+ // CHECK-FIXES-NEXT: Reg9.Reg = getReg();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned2.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned2.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned2.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned2.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s llvm-prefer-register-over-unsigned %t
+
+namespace llvm {
+class Register {
+public:
+ operator unsigned();
+};
+} // end namespace llvm
+
+llvm::Register getReg();
+
+using namespace llvm;
+
+void apply_1() {
+ unsigned Reg = getReg();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: variable 'Reg' declared as 'unsigned int'; use 'Register' instead [llvm-prefer-register-over-unsigned]
+ // CHECK-FIXES: apply_1()
+ // CHECK-FIXES-NEXT: Register Reg = getReg();
+}
+
+void done_1() {
+ llvm::Register Reg = getReg();
+ // CHECK-FIXES: done_1()
+ // CHECK-FIXES-NEXT: llvm::Register Reg = getReg();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned3.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned3.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned3.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned3.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s llvm-prefer-register-over-unsigned %t
+
+namespace llvm { };
+
+// This class shouldn't trigger it despite the similarity as it's not inside the llvm namespace
+class Register {
+public:
+ operator unsigned();
+};
+
+Register getReg();
+
+void do_nothing_1() {
+ unsigned Reg1 = getReg();
+ // CHECK-FIXES: do_nothing_1()
+ // CHECK-FIXES-NEXT: unsigned Reg1 = getReg();
+}
+
+void do_nothing_2() {
+ using namespace llvm;
+ unsigned Reg2 = getReg();
+ // CHECK-FIXES: do_nothing_2()
+ // CHECK-FIXES-NEXT: using namespace llvm;
+ // CHECK-FIXES-NEXT: unsigned Reg2 = getReg();
+}
+
+namespace llvm {
+void do_nothing_3() {
+ unsigned Reg3 = getReg();
+ // CHECK-FIXES: do_nothing_3()
+ // CHECK-FIXES-NEXT: unsigned Reg3 = getReg();
+}
+} // end namespace llvm
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-twine-local.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-twine-local.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-twine-local.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/llvm-twine-local.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,64 @@
+// RUN: %check_clang_tidy %s llvm-twine-local %t
+
+namespace llvm {
+class Twine {
+public:
+ Twine(const char *);
+ Twine(int);
+ Twine();
+ Twine &operator+(const Twine &);
+};
+}
+
+using namespace llvm;
+
+void foo(const Twine &x);
+
+static Twine Moo = Twine("bark") + "bah";
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: static std::string Moo = (Twine("bark") + "bah").str();
+
+int main() {
+ const Twine t = Twine("a") + "b" + Twine(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t = (Twine("a") + "b" + Twine(42)).str();
+ foo(Twine("a") + "b");
+
+ Twine Prefix = false ? "__INT_FAST" : "__UINT_FAST";
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: const char * Prefix = false ? "__INT_FAST" : "__UINT_FAST";
+
+ const Twine t2 = Twine();
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t2 = (Twine()).str();
+ foo(Twine() + "b");
+
+ const Twine t3 = Twine(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t3 = (Twine(42)).str();
+
+ const Twine t4 = Twine(42) + "b";
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t4 = (Twine(42) + "b").str();
+
+ const Twine t5 = Twine() + "b";
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t5 = (Twine() + "b").str();
+
+ const Twine t6 = true ? Twine() : Twine(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t6 = (true ? Twine() : Twine(42)).str();
+
+ const Twine t7 = false ? Twine() : Twine("b");
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t7 = (false ? Twine() : Twine("b")).str();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers-1z.hpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers-1z.hpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers-1z.hpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers-1z.hpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s misc-definitions-in-headers %t -- -- -std=c++1z
+
+class CE {
+ constexpr static int i = 5; // OK: inline variable definition.
+};
+
+inline int i = 5; // OK: inline variable definition.
+
+int b = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'b' defined in a header file; variable definitions in header files can lead to ODR violations [misc-definitions-in-headers]
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers.hpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers.hpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers.hpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-definitions-in-headers.hpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,194 @@
+// RUN: %check_clang_tidy %s misc-definitions-in-headers %t
+
+int f() {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'f' defined in a header file; function definitions in header files can lead to ODR violations [misc-definitions-in-headers]
+// CHECK-MESSAGES: :[[@LINE-2]]:5: note: make as 'inline'
+// CHECK-FIXES: inline int f() {
+ return 1;
+}
+
+class CA {
+ void f1() {} // OK: inline class member function definition.
+ void f2();
+ template<typename T>
+ T f3() {
+ T a = 1;
+ return a;
+ }
+ template<typename T>
+ struct CAA {
+ struct CAB {
+ void f4();
+ };
+ };
+};
+
+void CA::f2() { }
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: function 'f2' defined in a header file;
+// CHECK-FIXES: inline void CA::f2() {
+
+template <>
+int CA::f3() {
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: full function template specialization 'f3<int>' defined in a header file;
+// CHECK-FIXES: inline int CA::f3() {
+ int a = 1;
+ return a;
+}
+
+template <typename T>
+void CA::CAA<T>::CAB::f4() {
+// OK: member function definition of a nested template class in a class.
+}
+
+template <typename T>
+struct CB {
+ void f1();
+ struct CCA {
+ void f2(T a);
+ };
+ struct CCB; // OK: forward declaration.
+ static int a; // OK: class static data member declaration.
+};
+
+template <typename T>
+void CB<T>::f1() { // OK: Member function definition of a class template.
+}
+
+template <typename T>
+void CB<T>::CCA::f2(T a) {
+// OK: member function definition of a nested class in a class template.
+}
+
+template <typename T>
+struct CB<T>::CCB {
+ void f3();
+};
+
+template <typename T>
+void CB<T>::CCB::f3() {
+// OK: member function definition of a nested class in a class template.
+}
+
+template <typename T>
+int CB<T>::a = 2; // OK: static data member definition of a class template.
+
+template class CB<int>; // OK: explicitly instantiated static data member of a class template.
+inline int callCB() {
+ CB<double> cb; // OK: implicitly instantiated static data member of a class template.
+ return cb.a;
+}
+
+template <typename T>
+T tf() { // OK: template function definition.
+ T a;
+ return a;
+}
+
+
+namespace NA {
+ int f() { return 1; }
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: function 'f' defined in a header file;
+// CHECK-FIXES: inline int f() { return 1; }
+}
+
+template <typename T>
+T f3() {
+ T a = 1;
+ return a;
+}
+
+template <>
+int f3() {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: full function template specialization 'f3<int>' defined in a header file;
+// CHECK-FIXES: inline int f3() {
+ int a = 1;
+ return a;
+}
+
+int f5(); // OK: function declaration.
+inline int f6() { return 1; } // OK: inline function definition.
+namespace {
+ int f7() { return 1; }
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: function 'f7' defined in a header file;
+}
+
+int f8() = delete; // OK: the function being marked delete is not callable.
+
+template <typename T>
+int f9(T t) { return 1; }
+
+inline void callF9() { f9(1); } // OK: implicitly instantiated function.
+template int f9(double); // OK: explicitly instantiated function.
+
+int a = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'a' defined in a header file; variable definitions in header files can lead to ODR violations [misc-definitions-in-headers]
+CA a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:4: warning: variable 'a1' defined in a header file;
+
+namespace NB {
+ int b = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'b' defined in a header file;
+ const int c = 1; // OK: internal linkage variable definition.
+}
+
+class CC {
+ static int d; // OK: class static data member declaration.
+};
+
+int CC::d = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: variable 'd' defined in a header file;
+
+const char* ca = "foo";
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: variable 'ca' defined in a header file;
+
+namespace {
+ int e = 2;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'e' defined in a header file;
+}
+
+const char* const g = "foo"; // OK: internal linkage variable definition.
+static int h = 1; // OK: internal linkage variable definition.
+const int i = 1; // OK: internal linkage variable definition.
+extern int j; // OK: internal linkage variable definition.
+
+template <typename T, typename U>
+struct CD {
+ int f();
+};
+
+template <typename T>
+struct CD<T, int> {
+ int f();
+};
+
+template <>
+struct CD<int, int> {
+ int f();
+};
+
+int CD<int, int>::f() {
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: function 'f' defined in a header file;
+// CHECK-FIXES: inline int CD<int, int>::f() {
+ return 0;
+}
+
+template <typename T>
+int CD<T, int>::f() { // OK: partial template specialization.
+ return 0;
+}
+
+constexpr int k = 1; // OK: constexpr variable has internal linkage.
+
+constexpr int f10() { return 0; } // OK: constexpr function definition.
+
+const int f11() { return 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: function 'f11' defined in a header file;
+// CHECK-FIXES: inline const int f11() { return 0; }
+
+template <typename T>
+const T f12();
+
+template <>
+const int f12() { return 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: full function template specialization 'f12<int>' defined in a header file;
+// CHECK-FIXES: inline const int f12() { return 0; }
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const-cxx17.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const-cxx17.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const-cxx17.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const-cxx17.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,15 @@
+// RUN: %check_clang_tidy -expect-clang-tidy-error %s misc-misplaced-const %t -- -- -std=c++17
+
+// This test previously would cause a failed assertion because the structured
+// binding declaration had no valid type associated with it. This ensures the
+// expected clang diagnostic is generated instead.
+// CHECK-MESSAGES: :[[@LINE+1]]:6: error: decomposition declaration '[x]' requires an initializer [clang-diagnostic-error]
+auto [x];
+
+struct S { int a; };
+S f();
+
+int main() {
+ auto [x] = f();
+}
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,45 @@
+// RUN: %check_clang_tidy %s misc-misplaced-const %t
+
+typedef int plain_i;
+typedef int *ip;
+typedef const int *cip;
+
+typedef void (*func_ptr)(void);
+
+void func(void) {
+ // ok
+ const int *i0 = 0;
+ const plain_i *i1 = 0;
+ const cip i2 = 0; // const applies to both pointer and pointee.
+
+ // Not ok
+ const ip i3 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *'
+
+ ip const i4 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i4' declared with a const-qualified
+
+ const volatile ip i5 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i5' declared with a const-qualified typedef type; results in the type being 'int *const volatile' instead of 'const int *volatile'
+}
+
+void func2(const plain_i *i1,
+ const cip i2,
+ const ip i3,
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i3' declared with a const-qualified
+ const int *i4) {
+}
+
+struct S {
+ const int *i0;
+ const plain_i *i1;
+ const cip i2;
+ const ip i3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified
+};
+
+// Function pointers should not be diagnosed because a function
+// pointer type can never be const.
+void func3(const func_ptr fp) {
+ const func_ptr fp2 = fp;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-misplaced-const.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,44 @@
+// RUN: %check_clang_tidy %s misc-misplaced-const %t
+
+typedef int plain_i;
+typedef int *ip;
+typedef const int *cip;
+
+void func() {
+ if (const int *i = 0)
+ ;
+ if (const plain_i *i = 0)
+ ;
+ if (const cip i = 0)
+ ;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: 'i' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *'
+ if (const ip i = 0)
+ ;
+}
+
+template <typename Ty>
+struct S {
+ const Ty *i;
+ const Ty &i2;
+};
+
+template struct S<int>;
+template struct S<ip>; // ok
+template struct S<cip>;
+
+template <typename Ty>
+struct U {
+ const Ty *i;
+ const Ty &i2;
+};
+
+template struct U<int *>; // ok
+
+struct T {
+ typedef void (T::*PMF)();
+
+ void f() {
+ const PMF val = &T::f; // ok
+ }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads-sized-dealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads-sized-dealloc.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads-sized-dealloc.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads-sized-dealloc.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s misc-new-delete-overloads %t -- -- -fsized-deallocation
+
+typedef decltype(sizeof(int)) size_t;
+
+struct S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: declaration of 'operator delete' has no matching declaration of 'operator new' at the same scope [misc-new-delete-overloads]
+ void operator delete(void *ptr, size_t) noexcept; // not a placement delete
+};
+
+struct T {
+ // Because we have enabled sized deallocations explicitly, this new/delete
+ // pair matches.
+ void *operator new(size_t size) noexcept;
+ void operator delete(void *ptr, size_t) noexcept; // ok because sized deallocation is enabled
+};
+
+// While we're here, check that global operator delete with no operator new
+// is also matched.
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: declaration of 'operator delete' has no matching declaration of 'operator new' at the same scope
+void operator delete(void *ptr) noexcept;
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-new-delete-overloads.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,81 @@
+// RUN: %check_clang_tidy %s misc-new-delete-overloads %t
+
+typedef decltype(sizeof(int)) size_t;
+
+struct S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope [misc-new-delete-overloads]
+ void *operator new(size_t size) noexcept;
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new[]' has no matching declaration of 'operator delete[]' at the same scope
+ void *operator new[](size_t size) noexcept;
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+void *operator new(size_t size) noexcept(false);
+
+struct T {
+ // Sized deallocations are not enabled by default, and so this new/delete pair
+ // does not match. However, we expect only one warning, for the new, because
+ // the operator delete is a placement delete and we do not warn on mismatching
+ // placement operations.
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+ void *operator new(size_t size) noexcept;
+ void operator delete(void *ptr, size_t) noexcept; // ok only if sized deallocation is enabled
+};
+
+struct U {
+ void *operator new(size_t size) noexcept;
+ void operator delete(void *ptr) noexcept;
+
+ void *operator new[](size_t) noexcept;
+ void operator delete[](void *) noexcept;
+};
+
+struct Z {
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: declaration of 'operator delete' has no matching declaration of 'operator new' at the same scope
+ void operator delete(void *ptr) noexcept;
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: declaration of 'operator delete[]' has no matching declaration of 'operator new[]' at the same scope
+ void operator delete[](void *ptr) noexcept;
+};
+
+struct A {
+ void *operator new(size_t size, Z) noexcept; // ok, placement new
+};
+
+struct B {
+ void operator delete(void *ptr, A) noexcept; // ok, placement delete
+};
+
+// It is okay to have a class with an inaccessible free store operator.
+struct C {
+ void *operator new(size_t, A) noexcept; // ok, placement new
+private:
+ void operator delete(void *) noexcept;
+};
+
+// It is also okay to have a class with a delete free store operator.
+struct D {
+ void *operator new(size_t, A) noexcept; // ok, placement new
+ void operator delete(void *) noexcept = delete;
+};
+
+struct E : U {
+ void *operator new(size_t) noexcept; // okay, we inherit operator delete from U
+};
+
+struct F : S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+ void *operator new(size_t) noexcept;
+};
+
+class G {
+ void operator delete(void *) noexcept;
+};
+
+struct H : G {
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+ void *operator new(size_t) noexcept; // base class operator is inaccessible
+};
+
+template <typename Base> struct Derived : Base {
+ void operator delete(void *);
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,43 @@
+// RUN: %check_clang_tidy %s misc-non-copyable-objects %t
+
+typedef struct FILE {} FILE;
+typedef struct pthread_cond_t {} pthread_cond_t;
+typedef int pthread_mutex_t;
+
+// CHECK-MESSAGES: :[[@LINE+1]]:13: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'? [misc-non-copyable-objects]
+void g(FILE f);
+// CHECK-MESSAGES: :[[@LINE+1]]:24: warning: 'm' declared as type 'pthread_mutex_t', which is unsafe to copy; did you mean 'pthread_mutex_t *'?
+void h(pthread_mutex_t m);
+// CHECK-MESSAGES: :[[@LINE+1]]:23: warning: 'c' declared as type 'pthread_cond_t', which is unsafe to copy; did you mean 'pthread_cond_t *'?
+void i(pthread_cond_t c);
+
+struct S {
+ pthread_cond_t c; // ok
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ FILE f;
+};
+
+void func(FILE *f) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: 'f1' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ FILE f1; // match
+ // CHECK-MESSAGES: :[[@LINE+2]]:8: warning: 'f2' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ // CHECK-MESSAGES: :[[@LINE+1]]:13: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ FILE f2 = *f;
+ // CHECK-MESSAGES: :[[@LINE+1]]:15: warning: 'f3' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ struct FILE f3;
+ // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ (void)sizeof(*f);
+ (void)sizeof(FILE);
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ g(*f);
+
+ pthread_mutex_t m; // ok
+ h(m); // ok
+
+ pthread_cond_t c; // ok
+ i(c); // ok
+
+ pthread_mutex_t *m1 = &m; // ok
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: expression has opaque data structure type 'pthread_mutex_t'; type should only be used as a pointer and not dereferenced
+ h(*m1);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-copyable-objects.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s misc-non-copyable-objects %t
+
+namespace std {
+typedef struct FILE {} FILE;
+}
+using namespace std;
+
+// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'? [misc-non-copyable-objects]
+void g(std::FILE f);
+
+struct S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:10: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ ::FILE f;
+};
+
+void func(FILE *f) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:13: warning: 'f1' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ std::FILE f1; // match
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: 'f2' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ // CHECK-MESSAGES: :[[@LINE+1]]:15: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ ::FILE f2 = *f; // match, match
+ // CHECK-MESSAGES: :[[@LINE+1]]:15: warning: 'f3' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ struct FILE f3; // match
+ // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ (void)sizeof(*f); // match
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-private-member-variables-in-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-private-member-variables-in-classes.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-private-member-variables-in-classes.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-non-private-member-variables-in-classes.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,397 @@
+// RUN: %check_clang_tidy -check-suffixes=PUBLIC,NONPRIVATE,PROTECTED %s misc-non-private-member-variables-in-classes %t
+// RUN: %check_clang_tidy -check-suffixes=PUBLIC,NONPRIVATE,PROTECTED %s misc-non-private-member-variables-in-classes %t -- -config='{CheckOptions: [{key: misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables, value: 0}, {key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic, value: 0}]}' --
+// RUN: %check_clang_tidy -check-suffixes=PUBLIC,PROTECTED %s misc-non-private-member-variables-in-classes %t -- -config='{CheckOptions: [{key: misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables, value: 0}, {key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic, value: 1}]}' --
+// RUN: %check_clang_tidy -check-suffixes=PUBLIC,PROTECTED %s cppcoreguidelines-non-private-member-variables-in-classes %t -- --
+// RUN: %check_clang_tidy -check-suffixes=PROTECTED %s misc-non-private-member-variables-in-classes %t -- -config='{CheckOptions: [{key: misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables, value: 1}, {key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic, value: 0}]}' --
+// RUN: %check_clang_tidy -check-suffixes=PROTECTED %s misc-non-private-member-variables-in-classes %t -- -config='{CheckOptions: [{key: misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables, value: 1}, {key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic, value: 1}]}' --
+
+//----------------------------------------------------------------------------//
+
+// Only data, do not warn
+
+struct S0 {
+ int S0_v0;
+
+public:
+ int S0_v1;
+
+protected:
+ int S0_v2;
+
+private:
+ int S0_v3;
+};
+
+class S1 {
+ int S1_v0;
+
+public:
+ int S1_v1;
+
+protected:
+ int S1_v2;
+
+private:
+ int S1_v3;
+};
+
+// Only data and implicit or static methods, do not warn
+
+class C {
+public:
+ C() {}
+ ~C() {}
+};
+
+struct S1Implicit {
+ C S1Implicit_v0;
+};
+
+struct S1ImplicitAndStatic {
+ C S1Implicit_v0;
+ static void s() {}
+};
+
+//----------------------------------------------------------------------------//
+
+// All functions are static, do not warn.
+
+struct S2 {
+ static void S2_m0();
+ int S2_v0;
+
+public:
+ static void S2_m1();
+ int S2_v1;
+
+protected:
+ static void S2_m3();
+ int S2_v2;
+
+private:
+ static void S2_m4();
+ int S2_v3;
+};
+
+class S3 {
+ static void S3_m0();
+ int S3_v0;
+
+public:
+ static void S3_m1();
+ int S3_v1;
+
+protected:
+ static void S3_m3();
+ int S3_v2;
+
+private:
+ static void S3_m4();
+ int S3_v3;
+};
+
+//============================================================================//
+
+// union != struct/class. do not diagnose.
+
+union U0 {
+ void U0_m0();
+ int U0_v0;
+
+public:
+ void U0_m1();
+ int U0_v1;
+
+protected:
+ void U0_m2();
+ int U0_v2;
+
+private:
+ void U0_m3();
+ int U0_v3;
+};
+
+//============================================================================//
+
+// Has non-static method with default visibility.
+
+struct S4 {
+ void S4_m0();
+
+ int S4_v0;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S4_v0' has public visibility
+public:
+ int S4_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S4_v1' has public visibility
+protected:
+ int S4_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S4_v2' has protected visibility
+private:
+ int S4_v3;
+};
+
+class S5 {
+ void S5_m0();
+
+ int S5_v0;
+
+public:
+ int S5_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S5_v1' has public visibility
+protected:
+ int S5_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S5_v2' has protected visibility
+private:
+ int S5_v3;
+};
+
+//----------------------------------------------------------------------------//
+
+// Has non-static method with public visibility.
+
+struct S6 {
+ int S6_v0;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S6_v0' has public visibility
+public:
+ void S6_m0();
+ int S6_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S6_v1' has public visibility
+protected:
+ int S6_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S6_v2' has protected visibility
+private:
+ int S6_v3;
+};
+
+class S7 {
+ int S7_v0;
+
+public:
+ void S7_m0();
+ int S7_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S7_v1' has public visibility
+protected:
+ int S7_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S7_v2' has protected visibility
+private:
+ int S7_v3;
+};
+
+//----------------------------------------------------------------------------//
+
+// Has non-static method with protected visibility.
+
+struct S8 {
+ int S8_v0;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S8_v0' has public visibility
+public:
+ int S8_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S8_v1' has public visibility
+protected:
+ void S8_m0();
+ int S8_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S8_v2' has protected visibility
+private:
+ int S8_v3;
+};
+
+class S9 {
+ int S9_v0;
+
+public:
+ int S9_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S9_v1' has public visibility
+protected:
+ void S9_m0();
+ int S9_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S9_v2' has protected visibility
+private:
+ int S9_v3;
+};
+
+//----------------------------------------------------------------------------//
+
+// Has non-static method with private visibility.
+
+struct S10 {
+ int S10_v0;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S10_v0' has public visibility
+public:
+ int S10_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S10_v1' has public visibility
+protected:
+ int S10_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S10_v2' has protected visibility
+private:
+ void S10_m0();
+ int S10_v3;
+};
+
+class S11 {
+ int S11_v0;
+
+public:
+ int S11_v1;
+ // CHECK-MESSAGES-PUBLIC: :[[@LINE-1]]:7: warning: member variable 'S11_v1' has public visibility
+protected:
+ int S11_v2;
+ // CHECK-MESSAGES-PROTECTED: :[[@LINE-1]]:7: warning: member variable 'S11_v2' has protected visibility
+private:
+ void S11_m0();
+ int S11_v3;
+};
+
+//============================================================================//
+
+// Static variables are ignored.
+// Has non-static methods and static variables.
+
+struct S12 {
+ void S12_m0();
+ static int S12_v0;
+
+public:
+ void S12_m1();
+ static int S12_v1;
+
+protected:
+ void S12_m2();
+ static int S12_v2;
+
+private:
+ void S12_m3();
+ static int S12_v3;
+};
+
+class S13 {
+ void S13_m0();
+ static int S13_v0;
+
+public:
+ void S13_m1();
+ static int S13_v1;
+
+protected:
+ void S13_m2();
+ static int S13_v2;
+
+private:
+ void S13_m3();
+ static int S13_v3;
+};
+
+struct S14 {
+ void S14_m0();
+ int S14_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S14_v0' has public visibility
+
+public:
+ void S14_m1();
+ int S14_v1;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S14_v1' has public visibility
+
+protected:
+ void S14_m2();
+
+private:
+ void S14_m3();
+};
+
+class S15 {
+ void S15_m0();
+
+public:
+ void S15_m1();
+ int S15_v1;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S15_v1' has public visibility
+
+protected:
+ void S15_m2();
+
+private:
+ void S15_m3();
+};
+
+//----------------------------------------------------------------------------//
+
+template <typename T>
+struct S97 {
+ void method();
+ T S97_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:5: warning: member variable 'S97_v0' has public visibility
+};
+
+template struct S97<char *>;
+
+template <>
+struct S97<double> {
+ void method();
+ double S97d_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:10: warning: member variable 'S97d_v0' has public visibility
+};
+
+//----------------------------------------------------------------------------//
+
+#define FIELD(x) int x;
+
+// Do diagnose fields originating from macros.
+struct S98 {
+ void method();
+ FIELD(S98_v0);
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:9: warning: member variable 'S98_v0' has public visibility
+};
+
+//----------------------------------------------------------------------------//
+
+// Don't look in descendant classes.
+class S99 {
+ void method();
+
+ struct S99_0 {
+ int S99_S0_v0;
+ };
+
+public:
+ struct S99_1 {
+ int S99_S0_v0;
+ };
+
+protected:
+ struct S99_2 {
+ int S99_S0_v0;
+ };
+
+private:
+ struct S99_3 {
+ int S99_S0_v0;
+ };
+};
+
+//----------------------------------------------------------------------------//
+
+// Only diagnose once, don't let the inheritance fool you.
+struct S100 {
+ int S100_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S100_v0' has public visibility
+ void m0();
+};
+struct S101_default_inheritance : S100 {
+ int S101_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S101_v0' has public visibility
+ void m1();
+};
+struct S102_public_inheritance : public S100 {
+ int S102_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S102_v0' has public visibility
+ void m1();
+};
+struct S103_protected_inheritance : protected S100 {
+ int S103_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S103_v0' has public visibility
+ void m1();
+};
+struct S104_private_inheritance : private S100 {
+ int S104_v0;
+ // CHECK-MESSAGES-NONPRIVATE: :[[@LINE-1]]:7: warning: member variable 'S104_v0' has public visibility
+ void m1();
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-redundant-expression.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-redundant-expression.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-redundant-expression.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-redundant-expression.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,753 @@
+// RUN: %check_clang_tidy %s misc-redundant-expression %t -- -- -fno-delayed-template-parsing
+
+typedef __INT64_TYPE__ I64;
+
+struct Point {
+ int x;
+ int y;
+ int a[5];
+} P;
+
+extern Point P1;
+extern Point P2;
+
+extern int foo(int x);
+extern int bar(int x);
+extern int bat(int x, int y);
+
+int TestSimpleEquivalent(int X, int Y) {
+ if (X - X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent [misc-redundant-expression]
+ if (X / X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X % X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X & X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X | X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X ^ X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X < X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X <= X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X > X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X >= X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X && X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X || X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X != (((X)))) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X + 1 == X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X + 1 != X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X + 1 <= X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X + 1 >= X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+
+ if ((X != 1 || Y != 1) && (X != 1 || Y != 1)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: both sides of operator are equivalent
+ if (P.a[X - P.x] != P.a[X - P.x]) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: both sides of operator are equivalent
+
+ if ((int)X < (int)X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+ if (int(X) < int(X)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+
+ if ( + "dummy" == + "dummy") return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both sides of operator are equivalent
+ if (L"abc" == L"abc") return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+
+ if (foo(0) - 2 < foo(0) - 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both sides of operator are equivalent
+ if (foo(bar(0)) < (foo(bar((0))))) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both sides of operator are equivalent
+
+ if (P1.x < P2.x && P1.x < P2.x) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both sides of operator are equivalent
+ if (P2.a[P1.x + 2] < P2.x && P2.a[(P1.x) + (2)] < (P2.x)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: both sides of operator are equivalent
+
+ return 0;
+}
+
+template <int DX>
+int TestSimpleEquivalentDependent() {
+ if (DX > 0 && DX > 0) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+
+ return 0;
+}
+
+int Valid(int X, int Y) {
+ if (X != Y) return 1;
+ if (X == Y + 0) return 1;
+ if (P.x == P.y) return 1;
+ if (P.a[P.x] < P.a[P.y]) return 1;
+ if (P.a[0] < P.a[1]) return 1;
+
+ if (P.a[0] < P.a[0ULL]) return 1;
+ if (0 < 0ULL) return 1;
+ if ((int)0 < (int)0ULL) return 1;
+
+ if (++X != ++X) return 1;
+ if (P.a[X]++ != P.a[X]++) return 1;
+ if (P.a[X++] != P.a[X++]) return 1;
+
+ if ("abc" == "ABC") return 1;
+ if (foo(bar(0)) < (foo(bat(0, 1)))) return 1;
+ return 0;
+}
+
+#define COND_OP_MACRO 9
+#define COND_OP_OTHER_MACRO 9
+int TestConditional(int x, int y) {
+ int k = 0;
+ k += (y < 0) ? x : x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: 'true' and 'false' expressions are equivalent
+ k += (y < 0) ? x + 1 : x + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent
+ k += (y < 0) ? COND_OP_MACRO : COND_OP_MACRO;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: 'true' and 'false' expressions are equivalent
+
+ // Do not match for conditional operators with a macro and a const.
+ k += (y < 0) ? COND_OP_MACRO : 9;
+ // Do not match for conditional operators with expressions from different macros.
+ k += (y < 0) ? COND_OP_MACRO : COND_OP_OTHER_MACRO;
+ return k;
+}
+#undef COND_OP_MACRO
+#undef COND_OP_OTHER_MACRO
+
+// Overloaded operators that compare two instances of a struct.
+struct MyStruct {
+ int x;
+ bool operator==(const MyStruct& rhs) const {return this->x == rhs.x; } // not modifing
+ bool operator>=(const MyStruct& rhs) const { return this->x >= rhs.x; } // not modifing
+ bool operator<=(MyStruct& rhs) const { return this->x <= rhs.x; }
+ bool operator&&(const MyStruct& rhs){ this->x++; return this->x && rhs.x; }
+} Q;
+
+bool operator!=(const MyStruct& lhs, const MyStruct& rhs) { return lhs.x == rhs.x; } // not modifing
+bool operator<(const MyStruct& lhs, const MyStruct& rhs) { return lhs.x < rhs.x; } // not modifing
+bool operator>(const MyStruct& lhs, MyStruct& rhs) { rhs.x--; return lhs.x > rhs.x; }
+bool operator||(MyStruct& lhs, const MyStruct& rhs) { lhs.x++; return lhs.x || rhs.x; }
+
+bool TestOverloadedOperator(MyStruct& S) {
+ if (S == Q) return false;
+
+ if (S <= S) return false;
+ if (S && S) return false;
+ if (S > S) return false;
+ if (S || S) return false;
+
+ if (S == S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+ if (S < S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+ if (S != S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+ if (S >= S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+
+ return true;
+}
+
+#define LT(x, y) (void)((x) < (y))
+#define COND(x, y, z) ((x)?(y):(z))
+#define EQUALS(x, y) (x) == (y)
+
+int TestMacro(int X, int Y) {
+ LT(0, 0);
+ LT(1, 0);
+ LT(X, X);
+ LT(X+1, X + 1);
+ COND(X < Y, X, X);
+ EQUALS(Q, Q);
+ return 0;
+}
+
+int TestFalsePositive(int* A, int X, float F) {
+ // Produced by bison.
+ X = A[(2) - (2)];
+ X = A['a' - 'a'];
+
+ // Testing NaN.
+ if (F != F && F == F) return 1;
+ return 0;
+}
+
+int TestBannedMacros() {
+#define EAGAIN 3
+#define NOT_EAGAIN 3
+ if (EAGAIN == 0 | EAGAIN == 0) return 0;
+ if (NOT_EAGAIN == 0 | NOT_EAGAIN == 0) return 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: both sides of operator are equivalent
+ return 0;
+}
+
+struct MyClass {
+static const int Value = 42;
+};
+template <typename T, typename U>
+void TemplateCheck() {
+ static_assert(T::Value == U::Value, "should be identical");
+ static_assert(T::Value == T::Value, "should be identical");
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: both sides of operator are equivalent
+}
+void TestTemplate() { TemplateCheck<MyClass, MyClass>(); }
+
+int TestArithmetic(int X, int Y) {
+ if (X + 1 == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 != X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+ if (X - 1 == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X - 1 != X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1LL == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X + 1ULL == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false
+
+ if (X == X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false
+ if (X != X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+ if (X == X - 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false
+ if (X != X - 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+
+ if (X != X - 1U) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+ if (X != X - 1LL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+
+ if ((X+X) != (X+X) - 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X + 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 != X + 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X - 1 == X - 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X - 1 != X - 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X - -1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+ if (X + 1 != X - -1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 == X - -2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 != X - -2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X - (~0)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+ if (X + 1 == X - (~0U)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X - (~0ULL)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ // Should not match.
+ if (X + 0.5 == X) return 1;
+ if (X + 1 == Y) return 1;
+ if (X + 1 == Y + 1) return 1;
+ if (X + 1 == Y + 2) return 1;
+
+ return 0;
+}
+
+int TestBitwise(int X, int Y) {
+
+ if ((X & 0xFF) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((X & 0xFF) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+ if ((X | 0xFF) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((X | 0xFF) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+
+ if ((X | 0xFFULL) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: logical expression is always true
+ if ((X | 0xFF) != 0xF00ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+
+ if ((0xFF & X) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((0xFF & X) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+ if ((0xFF & X) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((0xFF & X) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+
+ if ((0xFFLL & X) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: logical expression is always false
+ if ((0xFF & X) == 0xF00ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+
+ return 0;
+}
+
+// Overloaded operators that compare an instance of a struct and an integer
+// constant.
+struct S {
+ S() { x = 1; }
+ int x;
+ // Overloaded comparison operators without any possible side effect.
+ bool operator==(const int &i) const { return x == i; } // not modifying
+ bool operator!=(int i) const { return x != i; } // not modifying
+ bool operator>(const int &i) const { return x > i; } // not modifying
+ bool operator<(int i) const { return x < i; } // not modifying
+};
+
+bool operator<=(const S &s, int i) { return s.x <= i; } // not modifying
+bool operator>=(const S &s, const int &i) { return s.x >= i; } // not modifying
+
+struct S2 {
+ S2() { x = 1; }
+ int x;
+ // Overloaded comparison operators that are able to modify their params.
+ bool operator==(const int &i) {
+ this->x++;
+ return x == i;
+ }
+ bool operator!=(int i) { return x != i; }
+ bool operator>(const int &i) { return x > i; }
+ bool operator<(int i) {
+ this->x--;
+ return x < i;
+ }
+};
+
+bool operator>=(S2 &s, const int &i) { return s.x >= i; }
+bool operator<=(S2 &s, int i) {
+ s.x++;
+ return s.x <= i;
+}
+
+int TestLogical(int X, int Y){
+#define CONFIG 0
+ if (CONFIG && X) return 1;
+#undef CONFIG
+#define CONFIG 1
+ if (CONFIG || X) return 1;
+#undef CONFIG
+
+ if (X == 10 && X != 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X == 10 && (X != 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X == 10 && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (!(X != 10) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+
+ if (X == 10ULL && X != 10ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if (!(X != 10U) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false
+ if (!(X != 10LL) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: logical expression is always false
+ if (!(X != 10ULL) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: logical expression is always false
+
+ if (X == 0 && X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X != 0 && !X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X && !X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false
+
+ if (X && !!X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: equivalent expression on both sides of logical operator
+ if (X != 0 && X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+ if (X != 0 && !!X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+ if (X == 0 && !X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+
+ // Should not match.
+ if (X == 10 && Y == 10) return 1;
+ if (X != 10 && X != 12) return 1;
+ if (X == 10 || X == 12) return 1;
+ if (!X && !Y) return 1;
+ if (!X && Y) return 1;
+ if (!X && Y == 0) return 1;
+ if (X == 10 && Y != 10) return 1;
+
+ // Test for overloaded operators with constant params.
+ S s1;
+ if (s1 == 1 && s1 == 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: equivalent expression on both sides of logical operator
+ if (s1 == 1 || s1 != 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+ if (s1 > 1 && s1 < 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (s1 >= 1 || s1 <= 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+
+ // Test for overloaded operators that may modify their params.
+ S2 s2;
+ if (s2 == 1 || s2 != 1) return true;
+ if (s2 == 1 || s2 == 1) return true;
+ if (s2 > 1 && s2 < 1) return true;
+ if (s2 >= 1 || s2 <= 1) return true;
+}
+
+int TestRelational(int X, int Y) {
+ if (X == 10 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X == 10 && X < 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X < 10 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X <= 10 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X < 10 && X >= 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X < 10 && X == 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+
+ if (X > 5 && X <= 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X > -5 && X <= -5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+
+ if (X < 10 || X >= 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always true
+ if (X <= 10 || X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+ if (X <= 10 || X >= 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+ if (X != 7 || X != 14) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always true
+ if (X == 7 || X != 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 7 || X == 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always true
+
+ if (X < 7 && X < 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X < 7 && X < 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X < 7 && X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+
+ if (X < 7 && X <= 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X < 7 && X <= 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: equivalent expression on both sides of logical operator
+ if (X < 7 && X <= 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+ if (X < 7 && X <= 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+
+ if (X <= 7 && X < 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X < 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+
+ if (X >= 7 && X > 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+ if (X >= 7 && X > 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X >= 7 && X > 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X <= 7 && X <= 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X <= 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X <= 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+ if (X <= 7 && X <= 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: expression is redundant
+
+ if (X == 11 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: expression is redundant
+ if (X == 11 && X < 12) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: expression is redundant
+ if (X > 10 && X == 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X < 12 && X == 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X != 11 && X == 42) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X > 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X < 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X > 14) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X < 7 || X < 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+ if (X < 7 || X < 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X < 7 || X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X > 7 || X > 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X > 7 || X > 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X > 7 || X > 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+
+ // Should not match.
+ if (X < 10 || X > 12) return 1;
+ if (X > 10 && X < 12) return 1;
+ if (X < 10 || X >= 12) return 1;
+ if (X > 10 && X <= 12) return 1;
+ if (X <= 10 || X > 12) return 1;
+ if (X >= 10 && X < 12) return 1;
+ if (X <= 10 || X >= 12) return 1;
+ if (X >= 10 && X <= 12) return 1;
+ if (X >= 10 && X <= 11) return 1;
+ if (X >= 10 && X < 11) return 1;
+ if (X > 10 && X <= 11) return 1;
+ if (X > 10 && X != 11) return 1;
+ if (X >= 10 && X <= 10) return 1;
+ if (X <= 10 && X >= 10) return 1;
+ if (X < 0 || X > 0) return 1;
+}
+
+int TestRelationalMacros(int X){
+#define SOME_MACRO 3
+#define SOME_MACRO_SAME_VALUE 3
+#define SOME_OTHER_MACRO 9
+ // Do not match for redundant relational macro expressions that can be
+ // considered intentional, and for some particular values, non redundant.
+
+ // Test cases for expressions with the same macro on both sides.
+ if (X < SOME_MACRO && X > SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always false
+ if (X < SOME_MACRO && X == SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always false
+ if (X < SOME_MACRO || X >= SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always true
+ if (X <= SOME_MACRO || X > SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: logical expression is always true
+ if (X != SOME_MACRO && X > SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != SOME_MACRO && X < SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ // Test cases for two different macros.
+ if (X < SOME_MACRO && X > SOME_OTHER_MACRO) return 1;
+ if (X != SOME_MACRO && X >= SOME_OTHER_MACRO) return 1;
+ if (X != SOME_MACRO && X != SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO || X == SOME_MACRO_SAME_VALUE) return 1;
+ if (X == SOME_MACRO || X <= SOME_MACRO_SAME_VALUE) return 1;
+ if (X == SOME_MACRO || X > SOME_MACRO_SAME_VALUE) return 1;
+ if (X < SOME_MACRO && X <= SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO && X > SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO && X != SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO && X != SOME_MACRO_SAME_VALUE) return 1;
+ if (X == SOME_MACRO_SAME_VALUE && X == SOME_MACRO ) return 1;
+
+ // Test cases for a macro and a const.
+ if (X < SOME_MACRO && X > 9) return 1;
+ if (X != SOME_MACRO && X >= 9) return 1;
+ if (X != SOME_MACRO && X != 9) return 1;
+ if (X == SOME_MACRO || X == 3) return 1;
+ if (X == SOME_MACRO || X <= 3) return 1;
+ if (X < SOME_MACRO && X <= 9) return 1;
+ if (X == SOME_MACRO && X != 9) return 1;
+ if (X == SOME_MACRO && X == 9) return 1;
+
+#undef SOME_OTHER_MACRO
+#undef SOME_MACRO_SAME_VALUE
+#undef SOME_MACRO
+ return 0;
+}
+
+int TestValidExpression(int X) {
+ if (X - 1 == 1 - X) return 1;
+ if (2 * X == X) return 1;
+ if ((X << 1) == X) return 1;
+
+ return 0;
+}
+
+enum Color { Red, Yellow, Green };
+int TestRelationalWithEnum(enum Color C) {
+ if (C == Red && C == Yellow) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false
+ if (C == Red && C != Red) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false
+ if (C != Red || C != Yellow) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always true
+
+ // Should not match.
+ if (C == Red || C == Yellow) return 1;
+ if (C != Red && C != Yellow) return 1;
+
+ return 0;
+}
+
+template<class T>
+int TestRelationalTemplated(int X) {
+ // This test causes a corner case with |isIntegerConstantExpr| where the type
+ // is dependent. There is an assert failing when evaluating
+ // sizeof(<incomplet-type>).
+ if (sizeof(T) == 4 || sizeof(T) == 8) return 1;
+
+ if (X + 0 == -X) return 1;
+ if (X + 0 < X) return 1;
+
+ return 0;
+}
+
+int TestWithSignedUnsigned(int X) {
+ if (X + 1 == X + 1ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if ((X & 0xFFU) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false
+
+ if ((X & 0xFF) == 0xF00U) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+
+ if ((X & 0xFFU) == 0xF00U) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false
+
+ return 0;
+}
+
+int TestWithLong(int X, I64 Y) {
+ if (X + 0ULL == -X) return 1;
+ if (Y + 0 == -Y) return 1;
+ if (Y <= 10 && X >= 10LL) return 1;
+ if (Y <= 10 && X >= 10ULL) return 1;
+ if (X <= 10 || X > 12LL) return 1;
+ if (X <= 10 || X > 12ULL) return 1;
+ if (Y <= 10 || Y > 12) return 1;
+
+ return 0;
+}
+
+int TestWithMinMaxInt(int X) {
+ if (X <= X + 0xFFFFFFFFU) return 1;
+ if (X <= X + 0x7FFFFFFF) return 1;
+ if (X <= X + 0x80000000) return 1;
+
+ if (X <= 0xFFFFFFFFU && X > 0) return 1;
+ if (X <= 0xFFFFFFFFU && X > 0U) return 1;
+
+ if (X + 0x80000000 == X - 0x80000000) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always true
+
+ if (X > 0x7FFFFFFF || X < ((-0x7FFFFFFF)-1)) return 1;
+ if (X <= 0x7FFFFFFF && X >= ((-0x7FFFFFFF)-1)) return 1;
+
+ return 0;
+}
+
+#define FLAG1 1
+#define FLAG2 2
+#define FLAG3 4
+#define FLAGS (FLAG1 | FLAG2 | FLAG3)
+#define NOTFLAGS !(FLAG1 | FLAG2 | FLAG3)
+int TestOperatorConfusion(int X, int Y, long Z)
+{
+ // Ineffective & expressions.
+ Y = (Y << 8) & 0xff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and operation
+ Y = (Y << 12) & 0xfff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Y = (Y << 12) & 0xff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Y = (Y << 8) & 0x77;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
+ Y = (Y << 5) & 0x11;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
+
+ // Tests for unmatched types
+ Z = (Z << 8) & 0xff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and operation
+ Y = (Y << 12) & 0xfffL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Z = (Y << 12) & 0xffLL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Y = (Z << 8L) & 0x77L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+
+ Y = (Y << 8) & 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
+
+ Y = (Y << 8) & -1;
+
+ // Effective expressions. Do not check.
+ Y = (Y << 4) & 0x15;
+ Y = (Y << 3) & 0x250;
+ Y = (Y << 9) & 0xF33;
+
+ int K = !(1 | 2 | 4);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: ineffective logical negation operator used; did you mean '~'?
+ // CHECK-FIXES: {{^}} int K = ~(1 | 2 | 4);{{$}}
+ K = !(FLAG1 & FLAG2 & FLAG3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} K = ~(FLAG1 & FLAG2 & FLAG3);{{$}}
+ K = !(3 | 4);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} K = ~(3 | 4);{{$}}
+ int NotFlags = !FLAGS;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} int NotFlags = ~FLAGS;{{$}}
+ NotFlags = NOTFLAGS;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: ineffective logical negation operator
+ return !(1 | 2 | 4);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} return ~(1 | 2 | 4);{{$}}
+}
+
+template <int Shift, int Mask>
+int TestOperatorConfusionDependent(int Y) {
+ int r1 = (Y << Shift) & 0xff;
+ int r2 = (Y << 8) & Mask;
+}
+#undef FLAG1
+#undef FLAG2
+#undef FLAG3
+
+namespace no_crash {
+struct Foo {};
+bool operator<(const Foo&, const Foo&);
+template <class T>
+struct Bar {
+ static const Foo &GetFoo();
+ static bool Test(const T & maybe_foo, const Foo& foo) {
+ return foo < GetFoo() && foo < maybe_foo;
+ }
+};
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,27 @@
+// RUN: %check_clang_tidy %s misc-static-assert %t -- -- -std=c11
+// RUN: clang-tidy %s -checks=-*,misc-static-assert -- -std=c99 | count 0
+
+void abort() {}
+#ifdef NDEBUG
+#define assert(x) 1
+#else
+#define assert(x) \
+ if (!(x)) \
+ abort()
+#endif
+
+void f(void) {
+ int x = 1;
+ assert(x == 0);
+ // CHECK-FIXES: {{^ }}assert(x == 0);
+
+ #define static_assert(x, msg) _Static_assert(x, msg)
+ assert(11 == 5 + 6);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(11 == 5 + 6, "");
+ #undef static_assert
+
+ assert(10 == 5 + 5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(10 == 5 + 5, "");
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-static-assert.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,143 @@
+// RUN: %check_clang_tidy %s misc-static-assert %t
+
+void abort() {}
+#ifdef NDEBUG
+#define assert(x) 1
+#else
+#define assert(x) \
+ if (!(x)) \
+ abort()
+#endif
+
+void print(...);
+
+#define ZERO_MACRO 0
+
+#define False false
+#define FALSE 0
+
+#define my_macro() assert(0 == 1)
+// CHECK-FIXES: #define my_macro() assert(0 == 1)
+
+constexpr bool myfunc(int a, int b) { return a * b == 0; }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" size_t strlen(const char *s);
+
+class A {
+public:
+ bool method() { return true; }
+};
+
+class B {
+public:
+ constexpr bool method() { return true; }
+};
+
+template <class T> void doSomething(T t) {
+ assert(myfunc(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
+ // CHECK-FIXES: {{^ }}static_assert(myfunc(1, 2), "");
+
+ assert(t.method());
+ // CHECK-FIXES: {{^ }}assert(t.method());
+
+ assert(sizeof(T) == 123);
+}
+
+int main() {
+ my_macro();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}my_macro();
+
+ assert(myfunc(1, 2) && (3 == 4));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(myfunc(1, 2) && (3 == 4), "");
+
+ int x = 1;
+ assert(x == 0);
+ // CHECK-FIXES: {{^ }}assert(x == 0);
+
+ A a;
+ B b;
+
+ doSomething<A>(a);
+ doSomething<B>(b);
+
+ assert(false);
+ // CHECK-FIXES: {{^ }}assert(false);
+
+ assert(False);
+ // CHECK-FIXES: {{^ }}assert(False);
+ assert(FALSE);
+ // CHECK-FIXES: {{^ }}assert(FALSE);
+
+ assert(ZERO_MACRO);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(ZERO_MACRO, "");
+
+ assert(!"Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(!"Don't report me!");
+
+ assert(0 && "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(0 && "Don't report me!");
+
+ assert(false && "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(false && "Don't report me!");
+
+#define NULL ((void*)0)
+ assert(NULL && "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(NULL && "Don't report me!");
+
+ assert(NULL == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(NULL == "Don't report me!");
+
+ assert("Don't report me!" == NULL);
+ // CHECK-FIXES: {{^ }}assert("Don't report me!" == NULL);
+
+ assert(0 == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(0 == "Don't report me!");
+
+#define NULL ((unsigned int)0)
+ assert(NULL && "Report me!");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(NULL , "Report me!");
+
+#define NULL __null
+ assert(__null == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(__null == "Don't report me!");
+ assert(NULL == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(NULL == "Don't report me!");
+#undef NULL
+
+ assert(ZERO_MACRO && "Report me!");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(ZERO_MACRO , "Report me!");
+
+ assert(0);
+
+#define false false
+ assert(false);
+
+#define false 0
+ assert(false);
+#undef false
+
+ assert(10==5 && "Report me!");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(10==5 , "Report me!");
+
+ assert(strlen("12345") == 5);
+ // CHECK-FIXES: {{^ }}assert(strlen("12345") == 5);
+
+#define assert(e) (__builtin_expect(!(e), 0) ? print (#e, __FILE__, __LINE__) : (void)0)
+ assert(false);
+ // CHECK-FIXES: {{^ }}assert(false);
+
+ assert(10 == 5 + 5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(10 == 5 + 5, "");
+#undef assert
+
+ return 0;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-throw-by-value-catch-by-reference.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-throw-by-value-catch-by-reference.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-throw-by-value-catch-by-reference.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-throw-by-value-catch-by-reference.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,156 @@
+// RUN: %check_clang_tidy %s misc-throw-by-value-catch-by-reference %t -- -- -fcxx-exceptions
+
+
+class logic_error {
+public:
+ logic_error(const char *message) {}
+};
+
+typedef logic_error *logic_ptr;
+typedef logic_ptr logic_double_typedef;
+
+int lastException;
+
+template <class T> struct remove_reference { typedef T type; };
+template <class T> struct remove_reference<T &> { typedef T type; };
+template <class T> struct remove_reference<T &&> { typedef T type; };
+
+template <typename T> typename remove_reference<T>::type &&move(T &&arg) {
+ return static_cast<typename remove_reference<T>::type &&>(arg);
+}
+
+logic_error CreateException() { return logic_error("created"); }
+
+void testThrowFunc() {
+ throw new logic_error("by pointer");
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
+ logic_ptr tmp = new logic_error("by pointer");
+ throw tmp;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
+ throw logic_error("by value");
+ auto *literal = "test";
+ throw logic_error(literal);
+ throw "test string literal";
+ throw L"throw wide string literal";
+ const char *characters = 0;
+ throw characters;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
+ logic_error lvalue("lvalue");
+ throw lvalue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+
+ throw move(lvalue);
+ int &ex = lastException;
+ throw ex;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ throw CreateException();
+}
+
+void throwReferenceFunc(logic_error &ref) { throw ref; }
+
+void catchByPointer() {
+ try {
+ testThrowFunc();
+ } catch (logic_error *e) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
+ }
+}
+
+void catchByValue() {
+ try {
+ testThrowFunc();
+ } catch (logic_error e) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches by value; should catch by reference instead [misc-throw-by-value-catch-by-reference]
+ }
+}
+
+void catchByReference() {
+ try {
+ testThrowFunc();
+ } catch (logic_error &e) {
+ }
+}
+
+void catchByConstReference() {
+ try {
+ testThrowFunc();
+ } catch (const logic_error &e) {
+ }
+}
+
+void catchTypedef() {
+ try {
+ testThrowFunc();
+ } catch (logic_ptr) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
+ }
+}
+
+void catchAll() {
+ try {
+ testThrowFunc();
+ } catch (...) {
+ }
+}
+
+void catchLiteral() {
+ try {
+ testThrowFunc();
+ } catch (const char *) {
+ } catch (const wchar_t *) {
+ // disabled for now until it is clear
+ // how to enable them in the test
+ //} catch (const char16_t*) {
+ //} catch (const char32_t*) {
+ }
+}
+
+// catching fundamentals should not warn
+void catchFundamental() {
+ try {
+ testThrowFunc();
+ } catch (int) {
+ } catch (double) {
+ } catch (unsigned long) {
+ }
+}
+
+struct TrivialType {
+ double x;
+ double y;
+};
+
+void catchTrivial() {
+ try {
+ testThrowFunc();
+ } catch (TrivialType) {
+ }
+}
+
+typedef logic_error &fine;
+void additionalTests() {
+ try {
+ } catch (int i) { // ok
+ throw i; // ok
+ } catch (fine e) { // ok
+ throw e; // ok
+ } catch (logic_error *e) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
+ throw e; // ok, despite throwing a pointer
+ } catch (...) { // ok
+ throw; // ok
+ }
+}
+
+struct S {};
+
+S &returnByReference();
+S returnByValue();
+
+void f() {
+ throw returnByReference(); // Should diagnose
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ throw returnByValue(); // Should not diagnose
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator-cxx17.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator-cxx17.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator-cxx17.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator-cxx17.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy -std=c++14-or-later %s misc-unconventional-assign-operator %t -- -- -fno-delayed-template-parsing
+
+struct BadModifier {
+ BadModifier& operator=(const BadModifier&) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const'
+};
+
+struct PR35468 {
+ template<typename T> auto &operator=(const T &) {
+ return *this;
+ }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unconventional-assign-operator.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,111 @@
+// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -isystem %S/Inputs/Headers -fno-delayed-template-parsing
+
+namespace std {
+template <typename T>
+struct remove_reference { typedef T type; };
+template <typename T>
+struct remove_reference<T &> { typedef T type; };
+template <typename T>
+struct remove_reference<T &&> { typedef T type; };
+template <typename T>
+typename remove_reference<T>::type &&move(T &&t);
+}
+
+
+struct Good {
+ Good& operator=(const Good&);
+ Good& operator=(Good&&);
+
+ // Assign from other types is fine too.
+ Good& operator=(int);
+};
+
+struct AlsoGood {
+ // By value is also fine.
+ AlsoGood& operator=(AlsoGood);
+};
+
+struct BadReturnType {
+ void operator=(const BadReturnType&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturnType&' [misc-unconventional-assign-operator]
+ const BadReturnType& operator=(BadReturnType&&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+ void operator=(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+};
+
+struct BadReturnType2 {
+ BadReturnType2&& operator=(const BadReturnType2&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+ int operator=(BadReturnType2&&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+};
+
+struct BadArgument {
+ BadArgument& operator=(BadArgument&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument'
+ BadArgument& operator=(const BadArgument&&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadAr
+};
+
+struct BadModifier {
+ BadModifier& operator=(const BadModifier&) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const'
+};
+
+struct Deleted {
+ // We don't check the return value of deleted operators.
+ void operator=(const Deleted&) = delete;
+ void operator=(Deleted&&) = delete;
+};
+
+class Private {
+ // We don't check the return value of private operators.
+ // Pre-C++11 way of disabling assignment.
+ void operator=(const Private &);
+};
+
+struct Virtual {
+ virtual Virtual& operator=(const Virtual &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual'
+};
+
+class BadReturnStatement {
+ int n;
+
+public:
+ BadReturnStatement& operator=(BadReturnStatement&& rhs) {
+ n = std::move(rhs.n);
+ return rhs;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this'
+ }
+
+ // Do not check if return type is different from '&BadReturnStatement'
+ int operator=(int i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+ n = i;
+ return n;
+ }
+};
+
+namespace pr31531 {
+enum E { e };
+// This declaration makes the 'return *this' below have an unresolved operator
+// in the class template, but not in an instantiation.
+E operator*(E, E);
+
+template <typename>
+struct UnresolvedOperator {
+ UnresolvedOperator &operator=(const UnresolvedOperator &) { return *this; }
+};
+
+UnresolvedOperator<int> UnresolvedOperatorInt;
+
+template <typename>
+struct Template {
+ Template &operator=(const Template &) { return this; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: operator=() should always return '*this'
+};
+
+Template<int> TemplateInt;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-uniqueptr-reset-release.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-uniqueptr-reset-release.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-uniqueptr-reset-release.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-uniqueptr-reset-release.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,69 @@
+// RUN: %check_clang_tidy %s misc-uniqueptr-reset-release %t
+
+namespace std {
+
+template <typename T>
+struct default_delete {};
+
+template <typename T, class Deleter = std::default_delete<T>>
+struct unique_ptr {
+ unique_ptr();
+ explicit unique_ptr(T *);
+ template <typename U, typename E>
+ unique_ptr(unique_ptr<U, E> &&);
+ void reset(T *);
+ T *release();
+};
+} // namespace std
+
+struct Foo {};
+struct Bar : Foo {};
+
+std::unique_ptr<Foo> Create();
+std::unique_ptr<Foo> &Look();
+std::unique_ptr<Foo> *Get();
+
+using FooFunc = void (*)(Foo *);
+using BarFunc = void (*)(Bar *);
+
+void f() {
+ std::unique_ptr<Foo> a, b;
+ std::unique_ptr<Bar> c;
+ std::unique_ptr<Foo> *x = &a;
+ std::unique_ptr<Foo> *y = &b;
+
+ a.reset(b.release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer ptr1 = std::move(ptr2) over ptr1.reset(ptr2.release()) [misc-uniqueptr-reset-release]
+ // CHECK-FIXES: a = std::move(b);
+ a.reset(c.release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: a = std::move(c);
+ a.reset(Create().release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer ptr = ReturnUnique() over ptr.reset(ReturnUnique().release()) [misc-uniqueptr-reset-release]
+ // CHECK-FIXES: a = Create();
+ x->reset(y->release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: *x = std::move(*y);
+ Look().reset(Look().release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: Look() = std::move(Look());
+ Get()->reset(Get()->release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: *Get() = std::move(*Get());
+
+ std::unique_ptr<Bar, FooFunc> func_a, func_b;
+ func_a.reset(func_b.release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: func_a = std::move(func_b);
+}
+
+void negatives() {
+ std::unique_ptr<Foo> src;
+ struct OtherDeleter {};
+ std::unique_ptr<Foo, OtherDeleter> dest;
+ dest.reset(src.release());
+
+ std::unique_ptr<Bar, FooFunc> func_a;
+ std::unique_ptr<Bar, BarFunc> func_b;
+ func_a.reset(func_b.release());
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-alias-decls.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-alias-decls.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-alias-decls.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-alias-decls.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy %s misc-unused-alias-decls %t
+
+namespace my_namespace {
+class C {};
+}
+
+namespace unused_alias = ::my_namespace; // eol-comments aren't removed (yet)
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: namespace alias decl 'unused_alias' is unused
+// CHECK-FIXES: {{^}}// eol-comments aren't removed (yet)
+
+namespace used_alias = ::my_namespace;
+void f() { used_alias::C c; }
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters-strict.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters-strict.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters-strict.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters-strict.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s misc-unused-parameters %t -- \
+// RUN: -config="{CheckOptions: [{key: StrictMode, value: 1}]}" --
+
+// Warn on empty function bodies in StrictMode.
+namespace strict_mode {
+void f(int foo) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'foo' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void f(int /*foo*/) {}{{$}}
+class E {
+ int i;
+
+public:
+ E(int j) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'j' is unused
+// CHECK-FIXES: {{^}} E(int /*j*/) {}{{$}}
+};
+class F {
+ int i;
+
+public:
+ F(int j) : i() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'j' is unused
+// CHECK-FIXES: {{^}} F(int /*j*/) : i() {}{{$}}
+};
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s misc-unused-parameters %t -- -- -xc
+
+// Basic removal
+// =============
+void a(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
+
+static void b(); // In C, forward declarations can leave out parameters.
+static void b(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}static void b() {;}{{$}}
+
+// Unchanged cases
+// ===============
+void h(i, c, d) int i; char *c, *d; {} // Don't mess with K&R style
+
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-parameters.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,278 @@
+// RUN: echo "static void staticFunctionHeader(int i) {;}" > %T/header.h
+// RUN: echo "static void staticFunctionHeader(int /*i*/) {;}" > %T/header-fixed.h
+// RUN: %check_clang_tidy -std=c++11 %s misc-unused-parameters %t -- -header-filter='.*' -- -fno-delayed-template-parsing
+// RUN: diff %T/header.h %T/header-fixed.h
+// FIXME: Make the test work in all language modes.
+
+#include "header.h"
+// CHECK-MESSAGES: header.h:1:38: warning
+
+// Basic removal
+// =============
+void a(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void a(int /*i*/) {;}{{$}}
+
+void b(int i = 1) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void b(int /*i*/ = 1) {;}{{$}}
+
+void c(int *i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void c(int * /*i*/) {;}{{$}}
+
+void d(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void d(int /*i*/[]) {;}{{$}}
+
+void e(int i[1]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void e(int /*i*/[1]) {;}{{$}}
+
+void f(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: parameter 'fn' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void f(void (* /*fn*/)()) {;}{{$}}
+
+// Unchanged cases
+// ===============
+void f(int i); // Don't remove stuff in declarations
+void g(int i = 1);
+void h(int i[]);
+void s(int i[1]);
+void u(void (*fn)());
+void w(int i) { (void)i; } // Don't remove used parameters
+
+bool useLambda(int (*fn)(int));
+static bool static_var = useLambda([] (int a) { return a; });
+
+// Remove parameters of local functions
+// ====================================
+static void staticFunctionA(int i);
+// CHECK-FIXES: {{^}}static void staticFunctionA();
+static void staticFunctionA(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionA()
+
+static void staticFunctionB(int i, int j) { (void)i; }
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning
+// CHECK-FIXES: {{^}}static void staticFunctionB(int i)
+
+static void staticFunctionC(int i, int j) { (void)j; }
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionC(int j)
+
+static void staticFunctionD(int i, int j, int k) { (void)i; (void)k; }
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning
+// CHECK-FIXES: {{^}}static void staticFunctionD(int i, int k)
+
+static void staticFunctionE(int i = 4) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionE()
+
+static void staticFunctionF(int i = 4);
+// CHECK-FIXES: {{^}}static void staticFunctionF();
+static void staticFunctionF(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionF()
+
+static void staticFunctionG(int i[]);
+// CHECK-FIXES: {{^}}static void staticFunctionG();
+static void staticFunctionG(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionG()
+
+static void staticFunctionH(void (*fn)());
+// CHECK-FIXES: {{^}}static void staticFunctionH();
+static void staticFunctionH(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning
+// CHECK-FIXES: {{^}}static void staticFunctionH()
+
+static void someCallSites() {
+ staticFunctionA(1);
+// CHECK-FIXES: staticFunctionA();
+ staticFunctionB(1, 2);
+// CHECK-FIXES: staticFunctionB(1);
+ staticFunctionC(1, 2);
+// CHECK-FIXES: staticFunctionC(2);
+ staticFunctionD(1, 2, 3);
+// CHECK-FIXES: staticFunctionD(1, 3);
+ staticFunctionE(1);
+// CHECK-FIXES: staticFunctionE();
+ staticFunctionF(1);
+// CHECK-FIXES: staticFunctionF();
+ staticFunctionF();
+// CHECK-FIXES: staticFunctionF();
+ int t[] = {1};
+ staticFunctionG(t);
+// CHECK-FIXES: staticFunctionG();
+ void func();
+ staticFunctionH(&func);
+// CHECK-FIXES: staticFunctionH();
+}
+
+/*
+ * FIXME: This fails because the removals overlap and ClangTidy doesn't apply
+ * them.
+ * static void bothVarsUnused(int a, int b) {;}
+ */
+
+// Regression test for long variable names and expressions
+// =======================================================
+static int variableWithLongName1(int LongName1, int LongName2) {
+// CHECK-MESSAGES: :[[@LINE-1]]:53: warning: parameter 'LongName2' is unused
+// CHECK-FIXES: {{^}}static int variableWithLongName1(int LongName1) {
+ return LongName1;
+}
+static int variableWithLongName2(int LongName1, int LongName2) {
+// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: parameter 'LongName1' is unused
+// CHECK-FIXES: {{^}}static int variableWithLongName2(int LongName2) {
+ return LongName2;
+}
+static void someLongNameCallSites() {
+ int LongName1 = 7, LongName2 = 17;
+ variableWithLongName1(LongName1, LongName2);
+// CHECK-FIXES: variableWithLongName1(LongName1);
+ variableWithLongName2(LongName1, LongName2);
+// CHECK-FIXES: variableWithLongName2(LongName2);
+}
+
+class SomeClass {
+ static void f(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
+// CHECK-FIXES: static void f(int /*i*/) {;}
+ static void g(int i = 1) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
+// CHECK-FIXES: static void g(int /*i*/ = 1) {;}
+ static void h(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
+// CHECK-FIXES: static void h(int /*i*/[]) {;}
+ static void s(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning
+// CHECK-FIXES: static void s(void (* /*fn*/)()) {;}
+};
+
+namespace {
+class C {
+public:
+ void f(int i);
+// CHECK-FIXES: void f();
+ void g(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void g() {;}
+ void h(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void h(int /*i*/) {;}
+ void s(int i = 1) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void s(int /*i*/ = 1) {;}
+ void u(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void u(int /*i*/[]) {;}
+ void w(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning
+// CHECK-FIXES: void w(void (* /*fn*/)()) {;}
+};
+
+void C::f(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning
+// CHECK-FIXES: void C::f() {;}
+
+template <typename T>
+void useFunction(T t);
+
+void someMoreCallSites() {
+ C c;
+ c.f(1);
+// CHECK-FIXES: c.f();
+ c.g(1);
+// CHECK-FIXES: c.g();
+
+ useFunction(&C::h);
+ useFunction(&C::s);
+ useFunction(&C::u);
+ useFunction(&C::w);
+}
+
+class Base {
+ virtual void f(int i);
+};
+
+class Derived : public Base {
+ void f(int i) override {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void f(int /*i*/) override {;}
+};
+
+} // end namespace
+
+template <typename T> void someFunctionTemplate(T b, T e) { (void)b; (void)e; }
+
+template <typename T> void someFunctionTemplateOneUnusedParam(T b, T e) { (void)e; }
+// CHECK-MESSAGES: :[[@LINE-1]]:65: warning
+// CHECK-FIXES: {{^}}template <typename T> void someFunctionTemplateOneUnusedParam(T /*b*/, T e) { (void)e; }
+
+template <typename T> void someFunctionTemplateAllUnusedParams(T b, T e) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:66: warning
+// CHECK-MESSAGES: :[[@LINE-2]]:71: warning
+// CHECK-FIXES: {{^}}template <typename T> void someFunctionTemplateAllUnusedParams(T /*b*/, T /*e*/) {;}
+
+static void dontGetConfusedByParametersInFunctionTypes() { void (*F)(int i); }
+
+template <typename T> class Function {};
+static Function<void(int, int i)> dontGetConfusedByFunctionReturnTypes() {
+ return Function<void(int, int)>();
+}
+
+namespace PR38055 {
+namespace {
+struct a {
+ void b(int c) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: parameter 'c' is unused
+// CHECK-FIXES: {{^}} void b() {;}{{$}}
+};
+template <class>
+class d {
+ a e;
+ void f() { e.b(); }
+};
+} // namespace
+} // namespace PR38055
+
+namespace strict_mode_off {
+// Do not warn on empty function bodies.
+void f1(int foo1) {}
+void f2(int foo2) {
+ // "empty" in the AST sense, not in textual sense.
+}
+void f3(int foo3) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: parameter 'foo3' is unused
+// CHECK-FIXES: {{^}}void f3(int /*foo3*/) {;}{{$}}
+
+class E {
+ int i;
+
+public:
+ E(int j) {}
+};
+class F {
+ int i;
+
+public:
+ // Constructor initializer counts as a non-empty body.
+ F(int j) : i() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'j' is unused
+// CHECK-FIXES: {{^}} F(int /*j*/) : i() {}{{$}}
+};
+
+class A {
+public:
+ A();
+ A(int);
+};
+class B : public A {
+public:
+ B(int i) : A() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is unused
+// CHECK-FIXES: {{^}} B(int /*i*/) : A() {}{{$}}
+};
+} // namespace strict_mode_off
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls-errors.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls-errors.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls-errors.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls-errors.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy -expect-clang-tidy-error %s misc-unused-using-decls %t
+
+namespace n {
+class C;
+}
+
+using n::C;
+
+void f() {
+ for (C *p : unknown()) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: error: use of undeclared identifier 'unknown' [clang-diagnostic-error]
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/misc-unused-using-decls.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,213 @@
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- -- -fno-delayed-template-parsing -isystem %S/Inputs/
+
+
+// ----- Definitions -----
+template <typename T> class vector {};
+namespace n {
+class A;
+class B;
+class C;
+class D;
+class D { public: static int i; };
+template <typename T> class E {};
+template <typename T> class F {};
+class G { public: static void func() {} };
+class H { public: static int i; };
+class I {
+ public:
+ static int ii;
+};
+template <typename T> class J {};
+class G;
+class H;
+
+template <typename T> class K {};
+template <template <typename> class S>
+class L {};
+
+template <typename T> class M {};
+class N {};
+
+template <int T> class P {};
+const int Constant = 0;
+
+template <typename T> class Q {};
+
+class Base {
+ public:
+ void f();
+};
+
+D UsedInstance;
+D UnusedInstance;
+
+int UsedFunc() { return 1; }
+int UnusedFunc() { return 1; }
+template <typename T> int UsedTemplateFunc() { return 1; }
+template <typename T> int UnusedTemplateFunc() { return 1; }
+template <typename T> int UsedInTemplateFunc() { return 1; }
+void OverloadFunc(int);
+void OverloadFunc(double);
+int FuncUsedByUsingDeclInMacro() { return 1; }
+
+class ostream {
+public:
+ ostream &operator<<(ostream &(*PF)(ostream &));
+};
+extern ostream cout;
+ostream &endl(ostream &os);
+
+enum Color1 { Green };
+
+enum Color2 { Red };
+
+enum Color3 { Yellow };
+
+enum Color4 { Blue };
+
+} // namespace n
+
+#include "unused-using-decls.h"
+namespace ns {
+template <typename T>
+class AA {
+ T t;
+};
+template <typename T>
+T ff() { T t; return t; }
+} // namespace ns
+
+// ----- Using declarations -----
+// eol-comments aren't removed (yet)
+using n::A; // A
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'A' is unused
+// CHECK-MESSAGES: :[[@LINE-2]]:10: note: remove the using
+// CHECK-FIXES: {{^}}// A
+using n::B;
+using n::C;
+using n::D;
+using n::E; // E
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'E' is unused
+// CHECK-FIXES: {{^}}// E
+using n::F;
+using n::G;
+using n::H;
+using n::I;
+int I::ii = 1;
+class Derived : public n::Base {
+ public:
+ using Base::f;
+};
+using n::UsedInstance;
+using n::UsedFunc;
+using n::UsedTemplateFunc;
+using n::UnusedInstance; // UnusedInstance
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedInstance' is unused
+// CHECK-FIXES: {{^}}// UnusedInstance
+using n::UnusedFunc; // UnusedFunc
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedFunc' is unused
+// CHECK-FIXES: {{^}}// UnusedFunc
+using n::cout;
+using n::endl;
+
+using n::UsedInTemplateFunc;
+using n::J;
+template <typename T> void Callee() {
+ J<T> j;
+ UsedInTemplateFunc<T>();
+}
+
+using n::OverloadFunc; // OverloadFunc
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'OverloadFunc' is unused
+// CHECK-FIXES: {{^}}// OverloadFunc
+
+#define DEFINE_INT(name) \
+ namespace INT { \
+ static const int _##name = 1; \
+ } \
+ using INT::_##name
+DEFINE_INT(test);
+#undef DEFIND_INT
+
+#define USING_FUNC \
+ using n::FuncUsedByUsingDeclInMacro;
+USING_FUNC
+#undef USING_FUNC
+
+namespace N1 {
+// n::G is used in namespace N2.
+// Currently, the check doesn't support multiple scopes. All the relevant
+// using-decls will be marked as used once we see an usage even the usage is in
+// other scope.
+using n::G;
+}
+
+namespace N2 {
+using n::G;
+void f(G g);
+}
+
+void IgnoreFunctionScope() {
+// Using-decls defined in function scope will be ignored.
+using n::H;
+}
+
+using n::Color1;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Color1' is unused
+using n::Green;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Green' is unused
+using n::Color2;
+using n::Color3;
+using n::Blue;
+
+using ns::AA;
+using ns::ff;
+
+using n::K;
+
+using n::N;
+
+// FIXME: Currently non-type template arguments are not supported.
+using n::Constant;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Constant' is unused
+
+using n::Q;
+
+// ----- Usages -----
+void f(B b);
+void g() {
+ vector<C> data;
+ D::i = 1;
+ F<int> f;
+ void (*func)() = &G::func;
+ int *i = &H::i;
+ UsedInstance.i;
+ UsedFunc();
+ UsedTemplateFunc<int>();
+ cout << endl;
+ Color2 color2;
+ int t1 = Color3::Yellow;
+ int t2 = Blue;
+
+ MyClass a;
+ int t3 = 0;
+ a.func1<AA>(&t3);
+ a.func2<int, ff>(t3);
+
+ n::L<K> l;
+}
+
+template<class T>
+void h(n::M<T>* t) {}
+// n::N is used the explicit template instantiation.
+template void h(n::M<N>* t);
+
+// Test on Non-type template arguments.
+template <int T>
+void i(n::P<T>* t) {}
+template void i(n::P<Constant>* t);
+
+template <typename T, template <typename> class U> class Bar {};
+// We used to report Q unsued, because we only checked the first template
+// argument.
+Bar<int, Q> *bar;
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-bind.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-bind.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-bind.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-bind.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,123 @@
+// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-avoid-bind %t
+
+namespace std {
+inline namespace impl {
+template <class Fp, class... Arguments>
+class bind_rt {};
+
+template <class Fp, class... Arguments>
+bind_rt<Fp, Arguments...> bind(Fp &&, Arguments &&...);
+}
+}
+
+int add(int x, int y) { return x + y; }
+
+void f() {
+ auto clj = std::bind(add, 2, 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind]
+ // CHECK-FIXES: auto clj = [] { return add(2, 2); };
+}
+
+void g() {
+ int x = 2;
+ int y = 2;
+ auto clj = std::bind(add, x, y);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto clj = [=] { return add(x, y); };
+}
+
+struct placeholder {};
+placeholder _1;
+placeholder _2;
+
+void h() {
+ int x = 2;
+ auto clj = std::bind(add, x, _1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto clj = [=](auto && arg1) { return add(x, arg1); };
+}
+
+struct A;
+struct B;
+bool ABTest(const A &, const B &);
+
+void i() {
+ auto BATest = std::bind(ABTest, _2, _1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto BATest = [](auto && arg1, auto && arg2) { return ABTest(arg2, arg1); };
+}
+
+void j() {
+ auto clj = std::bind(add, 2, 2, 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // No fix is applied for argument mismatches.
+ // CHECK-FIXES: auto clj = std::bind(add, 2, 2, 2);
+}
+
+void k() {
+ auto clj = std::bind(add, _1, _1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // No fix is applied for reused placeholders.
+ // CHECK-FIXES: auto clj = std::bind(add, _1, _1);
+}
+
+void m() {
+ auto clj = std::bind(add, 1, add(2, 5));
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // No fix is applied for nested calls.
+ // CHECK-FIXES: auto clj = std::bind(add, 1, add(2, 5));
+}
+
+namespace C {
+ int add(int x, int y){ return x + y; }
+}
+
+void n() {
+ auto clj = std::bind(C::add, 1, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto clj = [] { return C::add(1, 1); };
+}
+
+// Let's fake a minimal std::function-like facility.
+namespace std {
+template <typename _Tp>
+_Tp declval();
+
+template <typename _Functor, typename... _ArgTypes>
+struct __res {
+ template <typename... _Args>
+ static decltype(declval<_Functor>()(_Args()...)) _S_test(int);
+
+ template <typename...>
+ static void _S_test(...);
+
+ using type = decltype(_S_test<_ArgTypes...>(0));
+};
+
+template <typename>
+struct function;
+
+template <typename... _ArgTypes>
+struct function<void(_ArgTypes...)> {
+ template <typename _Functor,
+ typename = typename __res<_Functor, _ArgTypes...>::type>
+ function(_Functor) {}
+};
+} // namespace std
+
+struct Thing {};
+void UseThing(Thing *);
+
+struct Callback {
+ Callback();
+ Callback(std::function<void()>);
+ void Reset(std::function<void()>);
+};
+
+void test(Thing *t) {
+ Callback cb;
+ if (t)
+ cb.Reset(std::bind(UseThing, t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: cb.Reset([=] { return UseThing(t); });
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-main.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-main.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-main.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-main.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t
+
+int not_main(int argc, char *argv[]) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not declare C-style arrays, use std::array<> instead
+ int f4[] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+}
+
+int main(int argc, char *argv[]) {
+ int f5[] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+
+ auto not_main = [](int argc, char *argv[]) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: do not declare C-style arrays, use std::array<> instead
+ int f6[] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not declare C-style arrays, use std::array<> instead
+ };
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-three-arg-main.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-three-arg-main.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-three-arg-main.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays-ignores-three-arg-main.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t
+
+int not_main(int argc, char *argv[], char *argw[]) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not declare C-style arrays, use std::array<> instead
+ // CHECK-MESSAGES: :[[@LINE-2]]:38: warning: do not declare C-style arrays, use std::array<> instead
+ int f4[] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+}
+
+int main(int argc, char *argv[], char *argw[]) {
+ int f5[] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+
+ auto not_main = [](int argc, char *argv[], char *argw[]) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: do not declare C-style arrays, use std::array<> instead
+ // CHECK-MESSAGES: :[[@LINE-2]]:46: warning: do not declare C-style arrays, use std::array<> instead
+ int f6[] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not declare C-style arrays, use std::array<> instead
+ };
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-avoid-c-arrays.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,88 @@
+// RUN: %check_clang_tidy %s modernize-avoid-c-arrays %t
+
+int a[] = {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+int b[1];
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+void foo() {
+ int c[b[0]];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C VLA arrays, use std::vector<> instead
+
+ using d = decltype(c);
+ d e;
+ // Semi-FIXME: we do not diagnose these last two lines separately,
+ // because we point at typeLoc.getBeginLoc(), which is the decl before that
+ // (int c[b[0]];), which is already diagnosed.
+}
+
+template <typename T, int Size>
+class array {
+ T d[Size];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+
+ int e[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+};
+
+array<int[4], 2> d;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not declare C-style arrays, use std::array<> instead
+
+using k = int[4];
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not declare C-style arrays, use std::array<> instead
+
+array<k, 2> dk;
+
+template <typename T>
+class unique_ptr {
+ T *d;
+
+ int e[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+};
+
+unique_ptr<int[]> d2;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use std::array<> instead
+
+using k2 = int[];
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not declare C-style arrays, use std::array<> instead
+
+unique_ptr<k2> dk2;
+
+// Some header
+extern "C" {
+
+int f[] = {1, 2};
+
+int j[1];
+
+inline void bar() {
+ {
+ int j[j[0]];
+ }
+}
+
+extern "C++" {
+int f3[] = {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+int j3[1];
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not declare C-style arrays, use std::array<> instead
+
+struct Foo {
+ int f3[3] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+
+ int j3[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare C-style arrays, use std::array<> instead
+};
+}
+
+struct Bar {
+
+ int f[3] = {1, 2};
+
+ int j[1];
+};
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-concat-nested-namespaces.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-concat-nested-namespaces.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-concat-nested-namespaces.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-concat-nested-namespaces.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,161 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-concat-nested-namespaces %t
+
+namespace n1 {}
+
+namespace n2 {
+namespace n3 {
+void t();
+}
+namespace n4 {
+void t();
+}
+} // namespace n2
+
+namespace n5 {
+inline namespace n6 {
+void t();
+}
+} // namespace n5
+
+namespace n7 {
+void t();
+
+namespace n8 {
+void t();
+}
+} // namespace n7
+
+namespace n9 {
+namespace n10 {
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+// CHECK-FIXES: namespace n9::n10
+void t();
+} // namespace n10
+} // namespace n9
+// CHECK-FIXES: }
+
+namespace n11 {
+namespace n12 {
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+// CHECK-FIXES: namespace n11::n12
+namespace n13 {
+void t();
+}
+namespace n14 {
+void t();
+}
+} // namespace n12
+} // namespace n11
+// CHECK-FIXES: }
+
+namespace n15 {
+namespace n16 {
+void t();
+}
+
+inline namespace n17 {
+void t();
+}
+
+namespace n18 {
+namespace n19 {
+namespace n20 {
+// CHECK-MESSAGES: :[[@LINE-3]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+// CHECK-FIXES: namespace n18::n19::n20
+void t();
+} // namespace n20
+} // namespace n19
+} // namespace n18
+// CHECK-FIXES: }
+
+namespace n21 {
+void t();
+}
+} // namespace n15
+
+namespace n22 {
+namespace {
+void t();
+}
+} // namespace n22
+
+namespace n23 {
+namespace {
+namespace n24 {
+namespace n25 {
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+// CHECK-FIXES: namespace n24::n25
+void t();
+} // namespace n25
+} // namespace n24
+// CHECK-FIXES: }
+} // namespace
+} // namespace n23
+
+namespace n26::n27 {
+namespace n28 {
+namespace n29::n30 {
+// CHECK-MESSAGES: :[[@LINE-3]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+// CHECK-FIXES: namespace n26::n27::n28::n29::n30
+void t() {}
+} // namespace n29::n30
+} // namespace n28
+} // namespace n26::n27
+// CHECK-FIXES: }
+
+namespace n31 {
+namespace n32 {}
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+} // namespace n31
+// CHECK-FIXES-EMPTY
+
+namespace n33 {
+namespace n34 {
+namespace n35 {}
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+} // namespace n34
+// CHECK-FIXES-EMPTY
+namespace n36 {
+void t();
+}
+} // namespace n33
+
+namespace n37::n38 {
+void t();
+}
+
+#define IEXIST
+namespace n39 {
+namespace n40 {
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+// CHECK-FIXES: namespace n39::n40
+#ifdef IEXIST
+void t() {}
+#endif
+} // namespace n40
+} // namespace n39
+// CHECK-FIXES: }
+
+namespace n41 {
+namespace n42 {
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]
+// CHECK-FIXES: namespace n41::n42
+#ifdef IDONTEXIST
+void t() {}
+#endif
+} // namespace n42
+} // namespace n41
+// CHECK-FIXES: }
+
+int main() {
+ n26::n27::n28::n29::n30::t();
+#ifdef IEXIST
+ n39::n40::t();
+#endif
+
+#ifdef IDONTEXIST
+ n41::n42::t();
+#endif
+
+ return 0;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx03.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx03.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx03.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx03.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,148 @@
+// RUN: %check_clang_tidy -std=c++98 %s modernize-deprecated-headers %t -- -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers
+
+#include <assert.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead [modernize-deprecated-headers]
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include <complex.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include <ctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include <errno.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include <float.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include <limits.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include <locale.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include <math.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include <setjmp.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include <signal.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include <stdarg.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include <stddef.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include <stdio.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include <stdlib.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include <string.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include <time.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include <wchar.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include <wctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>{{$}}
+
+// Headers that have no effect in C++; remove them
+#include <stdalign.h> // <stdalign.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdalign.h>{{$}}
+#include <stdbool.h> // <stdbool.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdbool.h>{{$}}
+#include <iso646.h> // <iso646.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <iso646.h>{{$}}
+
+// Headers deprecated since C++11: expect no diagnostics.
+#include <fenv.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <tgmath.h>
+#include <uchar.h>
+
+
+#include "assert.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include "complex.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include "ctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include "errno.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include "float.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include "limits.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include "locale.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include "math.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include "setjmp.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include "signal.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include "stdarg.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include "stddef.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include "stdio.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include "stdlib.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include "string.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include "time.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include "wchar.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include "wctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>
+
+// Headers that have no effect in C++; remove them
+#include "stdalign.h" // "stdalign.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdalign.h"{{$}}
+#include "stdbool.h" // "stdbool.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdbool.h"{{$}}
+#include "iso646.h" // "iso646.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "iso646.h"{{$}}
+
+// Headers deprecated since C++11; expect no diagnostics
+#include "fenv.h"
+#include "inttypes.h"
+#include "stdint.h"
+#include "tgmath.h"
+#include "uchar.h"
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx11.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx11.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-headers-cxx11.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,163 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s modernize-deprecated-headers %t -- -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers
+
+#include <assert.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead [modernize-deprecated-headers]
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include <complex.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include <ctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include <errno.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include <fenv.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'fenv.h'; consider using 'cfenv' instead
+// CHECK-FIXES: {{^}}#include <cfenv>{{$}}
+#include <float.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include <inttypes.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'inttypes.h'; consider using 'cinttypes' instead
+// CHECK-FIXES: {{^}}#include <cinttypes>{{$}}
+#include <limits.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include <locale.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include <math.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include <setjmp.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include <signal.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include <stdarg.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include <stddef.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include <stdint.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdint.h'; consider using 'cstdint' instead
+// CHECK-FIXES: {{^}}#include <cstdint>{{$}}
+#include <stdio.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include <stdlib.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include <string.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include <tgmath.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'tgmath.h'; consider using 'ctgmath' instead
+// CHECK-FIXES: {{^}}#include <ctgmath>{{$}}
+#include <time.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include <uchar.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'uchar.h'; consider using 'cuchar' instead
+// CHECK-FIXES: {{^}}#include <cuchar>{{$}}
+#include <wchar.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include <wctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>
+
+// Headers that have no effect in C++; remove them
+#include <stdalign.h> // <stdalign.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdalign.h>{{$}}
+#include <stdbool.h> // <stdbool.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdbool.h>{{$}}
+#include <iso646.h> // <iso646.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <iso646.h>{{$}}
+
+#include "assert.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include "complex.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include "ctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include "errno.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include "fenv.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'fenv.h'; consider using 'cfenv' instead
+// CHECK-FIXES: {{^}}#include <cfenv>{{$}}
+#include "float.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include "inttypes.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'inttypes.h'; consider using 'cinttypes' instead
+// CHECK-FIXES: {{^}}#include <cinttypes>{{$}}
+#include "limits.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include "locale.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include "math.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include "setjmp.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include "signal.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include "stdarg.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include "stddef.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include "stdint.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdint.h'; consider using 'cstdint' instead
+// CHECK-FIXES: {{^}}#include <cstdint>{{$}}
+#include "stdio.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include "stdlib.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include "string.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include "tgmath.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'tgmath.h'; consider using 'ctgmath' instead
+// CHECK-FIXES: {{^}}#include <ctgmath>{{$}}
+#include "time.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include "uchar.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'uchar.h'; consider using 'cuchar' instead
+// CHECK-FIXES: {{^}}#include <cuchar>{{$}}
+#include "wchar.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include "wctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>
+
+// Headers that have no effect in C++; remove them
+#include "stdalign.h" // "stdalign.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdalign.h"{{$}}
+#include "stdbool.h" // "stdbool.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdbool.h"{{$}}
+#include "iso646.h" // "iso646.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "iso646.h"{{$}}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-ios-base-aliases.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-ios-base-aliases.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-ios-base-aliases.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-deprecated-ios-base-aliases.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,239 @@
+// RUN: %check_clang_tidy %s modernize-deprecated-ios-base-aliases %t
+
+namespace std {
+class ios_base {
+public:
+ typedef int io_state;
+ typedef int open_mode;
+ typedef int seek_dir;
+
+ typedef int streampos;
+ typedef int streamoff;
+};
+
+template <class CharT>
+class basic_ios : public ios_base {
+};
+} // namespace std
+
+// Test function return values (declaration)
+std::ios_base::io_state f_5();
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'std::ios_base::io_state' is deprecated; use 'std::ios_base::iostate' instead [modernize-deprecated-ios-base-aliases]
+// CHECK-FIXES: std::ios_base::iostate f_5();
+
+// Test function parameters.
+void f_6(std::ios_base::open_mode);
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 'std::ios_base::open_mode' is deprecated
+// CHECK-FIXES: void f_6(std::ios_base::openmode);
+void f_7(const std::ios_base::seek_dir &);
+// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 'std::ios_base::seek_dir' is deprecated
+// CHECK-FIXES: void f_7(const std::ios_base::seekdir &);
+
+// Test on record type fields.
+struct A {
+ std::ios_base::io_state field;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std::ios_base::iostate field;
+
+ typedef std::ios_base::io_state int_ptr_type;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: typedef std::ios_base::iostate int_ptr_type;
+};
+
+struct B : public std::ios_base {
+ io_state a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: iostate a;
+};
+
+struct C : public std::basic_ios<char> {
+ io_state a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: iostate a;
+};
+
+void f_1() {
+ std::ios_base::io_state a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std::ios_base::iostate a;
+
+ // Check that spaces aren't modified unnecessarily.
+ std :: ios_base :: io_state b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std :: ios_base :: iostate b;
+
+ // Test construction from a temporary.
+ std::ios_base::io_state c = std::ios_base::io_state{};
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:46: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std::ios_base::iostate c = std::ios_base::iostate{};
+
+ typedef std::ios_base::io_state alias1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: typedef std::ios_base::iostate alias1;
+ alias1 d(a);
+
+ using alias2 = std::ios_base::io_state;
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: using alias2 = std::ios_base::iostate;
+ alias2 e;
+
+ // Test pointers.
+ std::ios_base::io_state *f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std::ios_base::iostate *f;
+
+ // Test 'static' declarations.
+ static std::ios_base::io_state g;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: static std::ios_base::iostate g;
+
+ // Test with cv-qualifiers.
+ const std::ios_base::io_state h(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: const std::ios_base::iostate h(0);
+ volatile std::ios_base::io_state i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: volatile std::ios_base::iostate i;
+ const volatile std::ios_base::io_state j(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: const volatile std::ios_base::iostate j(0);
+
+ // Test auto and initializer-list.
+ auto k = std::ios_base::io_state{};
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: auto k = std::ios_base::iostate{};
+
+ std::ios_base::io_state l{std::ios_base::io_state()};
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std::ios_base::iostate l{std::ios_base::iostate()};
+
+ // Test temporaries.
+ std::ios_base::io_state();
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std::ios_base::iostate();
+
+ // Test inherited type usage
+ std::basic_ios<char>::io_state m;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: std::basic_ios<char>::iostate m;
+
+ std::ios_base::streampos n;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::streampos' is deprecated [modernize-deprecated-ios-base-aliases]
+
+ std::ios_base::streamoff o;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'std::ios_base::streamoff' is deprecated [modernize-deprecated-ios-base-aliases]
+}
+
+// Test without the nested name specifiers.
+void f_2() {
+ using namespace std;
+
+ ios_base::io_state a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: ios_base::iostate a;
+}
+
+// Test messing-up with macros.
+void f_4() {
+#define MACRO_1 std::ios_base::io_state
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: 'std::ios_base::io_state' is deprecated
+ MACRO_1 a;
+
+#define MACRO_2 io_state
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: 'std::ios_base::io_state' is deprecated
+ std::ios_base::MACRO_2 b;
+
+#define MACRO_3 std::ios_base
+ MACRO_3::io_state c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'std::ios_base::io_state' is deprecated
+
+#define MACRO_4(type) type::io_state
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 'std::ios_base::io_state' is deprecated
+ MACRO_4(std::ios_base) d;
+
+#undef MACRO_1
+#undef MACRO_2
+#undef MACRO_3
+#undef MACRO_4
+}
+
+// Test function return values (definition).
+std::ios_base::io_state f_5()
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'std::ios_base::io_state' is deprecated
+// CHECK-FIXES: std::ios_base::iostate f_5()
+{
+ // Test constructor.
+ return std::ios_base::io_state(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: return std::ios_base::iostate(0);
+}
+
+// Test that other aliases with same name aren't replaced
+struct my_ios_base {
+ typedef int io_state;
+};
+
+namespace ns_1 {
+struct my_ios_base2 {
+ typedef int io_state;
+};
+} // namespace ns_1
+
+void f_8() {
+ my_ios_base::io_state a;
+
+ ns_1::my_ios_base2::io_state b;
+}
+
+// Test templates
+template <typename X>
+void f_9() {
+ typename std::basic_ios<X>::io_state p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 'std::ios_base::io_state' is deprecated
+ typename std::ios_base::io_state q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: typename std::ios_base::iostate q;
+}
+
+template <typename T>
+void f_10(T arg) {
+ T x(arg);
+}
+
+template <typename T>
+void f_11() {
+ typename T::io_state x{};
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'std::ios_base::io_state' is deprecated
+}
+
+template <typename T>
+struct D : std::ios_base {
+ io_state a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: iostate a;
+
+ typename std::basic_ios<T>::io_state b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 'std::ios_base::io_state' is deprecated
+};
+
+template <typename T>
+struct E {
+ T t;
+};
+
+void f_12() {
+ f_9<char>();
+
+ f_10<std::ios_base::io_state>(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: f_10<std::ios_base::iostate>(0);
+
+ f_11<std::ios_base>();
+ D<char> d;
+
+ E<std::ios_base::io_state> e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: 'std::ios_base::io_state' is deprecated
+ // CHECK-FIXES: E<std::ios_base::iostate> e;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-assert-failure.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-assert-failure.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-assert-failure.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-assert-failure.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,18 @@
+// RUN: not clang-tidy %s -checks=-*,modernize-loop-convert --
+
+// Note: this test expects no assert failure happened in clang-tidy.
+
+class LinguisticItem {
+ LinguisticItem *x0;
+ class x1 {
+ bool operator!= ( const x1 &;
+ operator* ( ;
+ LinguisticItem * &operator-> ( ;
+ operator++ (
+ } begin() const;
+ x1 end() const {
+ LinguisticStream x2;
+ for (x1 x3 = x2.begin x3 != x2.end; ++x3)
+ x3->x0
+ }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-basic.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-basic.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-basic.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-basic.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,796 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+namespace Array {
+
+const int N = 6;
+const int NMinusOne = N - 1;
+int Arr[N] = {1, 2, 3, 4, 5, 6};
+const int ConstArr[N] = {1, 2, 3, 4, 5, 6};
+int (*PArr)[N] = &Arr;
+
+void f() {
+ int Sum = 0;
+
+ for (int I = 0; I < N; ++I) {
+ Sum += Arr[I];
+ int K;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: Sum += I;
+ // CHECK-FIXES-NEXT: int K;
+
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number is %d\n", Arr[I]);
+ Sum += Arr[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0; I < N; ++I) {
+ int X = Arr[I];
+ int Y = Arr[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: int X = I;
+ // CHECK-FIXES-NEXT: int Y = I + 2;
+
+ for (int I = 0; I < N; ++I) {
+ int X = N;
+ X = Arr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: int X = N;
+ // CHECK-FIXES-NEXT: X = I;
+
+ for (int I = 0; I < N; ++I) {
+ Arr[I] += 1;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: I += 1;
+
+ for (int I = 0; I < N; ++I) {
+ int X = Arr[I] + 2;
+ Arr[I]++;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: int X = I + 2;
+ // CHECK-FIXES-NEXT: I++;
+
+ for (int I = 0; I < N; ++I) {
+ Arr[I] = 4 + Arr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: I = 4 + I;
+
+ for (int I = 0; I < NMinusOne + 1; ++I) {
+ Sum += Arr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: Sum += I;
+
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number %d has address %p\n", Arr[I], &Arr[I]);
+ Sum += Arr[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number %d has address %p\n", I, &I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ Val Teas[N];
+ for (int I = 0; I < N; ++I) {
+ Teas[I].g();
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Tea : Teas)
+ // CHECK-FIXES-NEXT: Tea.g();
+}
+
+const int *constArray() {
+ for (int I = 0; I < N; ++I) {
+ printf("2 * %d = %d\n", ConstArr[I], ConstArr[I] + ConstArr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : ConstArr)
+ // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I, I + I);
+
+ const NonTriviallyCopyable NonCopy[N]{};
+ for (int I = 0; I < N; ++I) {
+ printf("2 * %d = %d\n", NonCopy[I].X, NonCopy[I].X + NonCopy[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : NonCopy)
+ // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I.X, I.X + I.X);
+
+ const TriviallyCopyableButBig Big[N]{};
+ for (int I = 0; I < N; ++I) {
+ printf("2 * %d = %d\n", Big[I].X, Big[I].X + Big[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : Big)
+ // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I.X, I.X + I.X);
+
+ bool Something = false;
+ for (int I = 0; I < N; ++I) {
+ if (Something)
+ return &ConstArr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const int & I : ConstArr)
+ // CHECK-FIXES-NEXT: if (Something)
+ // CHECK-FIXES-NEXT: return &I;
+}
+
+struct HasArr {
+ int Arr[N];
+ Val ValArr[N];
+ void implicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+
+ void explicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : this->Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : this->ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+};
+
+struct HasIndirectArr {
+ HasArr HA;
+ void implicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", HA.Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : HA.Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", HA.ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : HA.ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+
+ void explicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->HA.Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : this->HA.Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->HA.ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : this->HA.ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+};
+
+// Loops whose bounds are value-dependent should not be converted.
+template <int N>
+void dependentExprBound() {
+ for (int I = 0; I < N; ++I)
+ Arr[I] = 0;
+}
+template void dependentExprBound<20>();
+
+void memberFunctionPointer() {
+ Val V;
+ void (Val::*mfpArr[N])(void) = {&Val::g};
+ for (int I = 0; I < N; ++I)
+ (V.*mfpArr[I])();
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : mfpArr)
+ // CHECK-FIXES-NEXT: (V.*I)();
+
+ struct Foo {
+ int (Val::*f)();
+ } Foo[N];
+
+ for (int I = 0; I < N; ++I)
+ int R = (V.*(Foo[I].f))();
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Foo)
+ // CHECK-FIXES-NEXT: int R = (V.*(I.f))();
+
+}
+
+} // namespace Array
+
+namespace Iterator {
+
+void f() {
+ /// begin()/end() - based for loops here:
+ T Tt;
+ for (T::iterator It = Tt.begin(), E = Tt.end(); It != E; ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Tt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ T *Pt;
+ for (T::iterator It = Pt->begin(), E = Pt->end(); It != E; ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : *Pt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ S Ss;
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::iterator It = Ps->begin(), E = Ps->end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ for (S::const_iterator It = Ss.cbegin(), E = Ss.cend(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ It->X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ (*It).X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ It->nonConstFun(4, 5);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.nonConstFun(4, 5);
+
+ U Uu;
+ for (U::iterator It = Uu.begin(), E = Uu.end(); It != E; ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (U::iterator It = Uu.begin(), E = Uu.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (U::iterator It = Uu.begin(), E = Uu.end(); It != E; ++It) {
+ Val* a = It.operator->();
+ }
+
+ U::iterator A;
+ for (U::iterator I = Uu.begin(), E = Uu.end(); I != E; ++I)
+ int K = A->X + I->X;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Uu)
+ // CHECK-FIXES-NEXT: int K = A->X + I.X;
+
+ dependent<int> V;
+ for (dependent<int>::iterator It = V.begin(), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ for (dependent<int>::iterator It(V.begin()), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ doublyDependent<int, int> Intmap;
+ for (doublyDependent<int, int>::iterator It = Intmap.begin(), E = Intmap.end();
+ It != E; ++It) {
+ printf("Intmap[%d] = %d", It->first, It->second);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Intmap)
+ // CHECK-FIXES: printf("Intmap[%d] = %d", It.first, It.second);
+
+ // PtrSet's iterator dereferences by value so auto & can't be used.
+ {
+ PtrSet<int *> Val_int_ptrs;
+ for (PtrSet<int *>::iterator I = Val_int_ptrs.begin(),
+ E = Val_int_ptrs.end();
+ I != E; ++I) {
+ (void) *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Val_int_ptr : Val_int_ptrs)
+ }
+
+ // This container uses an iterator where the dereference type is a typedef of
+ // a reference type. Make sure non-const auto & is still used. A failure here
+ // means canonical types aren't being tested.
+ {
+ TypedefDerefContainer<int> Int_ptrs;
+ for (TypedefDerefContainer<int>::iterator I = Int_ptrs.begin(),
+ E = Int_ptrs.end();
+ I != E; ++I) {
+ (void) *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & Int_ptr : Int_ptrs)
+ }
+
+ {
+ // Iterators returning an rvalue reference should disqualify the loop from
+ // transformation.
+ RValueDerefContainer<int> Container;
+ for (RValueDerefContainer<int>::iterator I = Container.begin(),
+ E = Container.end();
+ I != E; ++I) {
+ (void) *I;
+ }
+ }
+
+ dependent<Val *> Dpp;
+ for (dependent<Val *>::iterator I = Dpp.begin(), E = Dpp.end(); I != E; ++I) {
+ printf("%d\n", (**I).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Dpp)
+ // CHECK-FIXES-NEXT: printf("%d\n", (*I).X);
+
+ for (dependent<Val *>::iterator I = Dpp.begin(), E = Dpp.end(); I != E; ++I) {
+ printf("%d\n", (*I)->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Dpp)
+ // CHECK-FIXES-NEXT: printf("%d\n", I->X);
+}
+
+// Tests to verify the proper use of auto where the init variable type and the
+// initializer type differ or are mostly the same except for const qualifiers.
+void different_type() {
+ // Ss.begin() returns a type 'iterator' which is just a non-const pointer and
+ // differs from const_iterator only on the const qualification.
+ S Ss;
+ for (S::const_iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::const_iterator It = Ps->begin(), E = Ps->end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ dependent<int> V;
+ for (dependent<int>::const_iterator It = V.begin(), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ for (dependent<int>::const_iterator It(V.begin()), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+}
+
+// Tests to ensure that an implicit 'this' is picked up as the container.
+// If member calls are made to 'this' within the loop, the transform becomes
+// risky as these calls may affect state that affects the loop.
+class C {
+public:
+ typedef MutableVal *iterator;
+ typedef const MutableVal *const_iterator;
+
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ void doSomething();
+ void doSomething() const;
+
+ void doLoop() {
+ for (iterator I = begin(), E = end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+
+ for (iterator I = C::begin(), E = C::end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ (void) *I;
+ doSomething();
+ }
+
+ for (iterator I = begin(); I != end(); ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+
+ for (iterator I = begin(); I != end(); ++I) {
+ (void) *I;
+ doSomething();
+ }
+ }
+
+ void doLoop() const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto I : *this)
+
+ for (const_iterator I = C::begin(), E = C::end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto I : *this)
+
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ (void) *I;
+ doSomething();
+ }
+ }
+};
+
+class C2 {
+public:
+ typedef MutableVal *iterator;
+
+ iterator begin() const;
+ iterator end() const;
+
+ void doLoop() {
+ // The implicit 'this' will have an Implicit cast to const C2* wrapped
+ // around it. Make sure the replacement still happens.
+ for (iterator I = begin(), E = end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+ }
+};
+
+} // namespace Iterator
+
+namespace PseudoArray {
+
+const int N = 6;
+dependent<int> V;
+dependent<int> *Pv;
+const dependent<NonTriviallyCopyable> Constv;
+const dependent<NonTriviallyCopyable> *Pconstv;
+
+transparent<dependent<int>> Cv;
+
+void f() {
+ int Sum = 0;
+ for (int I = 0, E = V.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", V[I]);
+ Sum += V[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0, E = V.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", V.at(I));
+ Sum += V.at(I) + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0, E = Pv->size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Pv->at(I));
+ Sum += Pv->at(I) + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : *Pv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ // This test will fail if size() isn't called repeatedly, since it
+ // returns unsigned int, and 0 is deduced to be signed int.
+ // FIXME: Insert the necessary explicit conversion, or write out the types
+ // explicitly.
+ for (int I = 0; I < Pv->size(); ++I) {
+ printf("Fibonacci number is %d\n", (*Pv).at(I));
+ Sum += (*Pv)[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : *Pv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0; I < Cv->size(); ++I) {
+ printf("Fibonacci number is %d\n", Cv->at(I));
+ Sum += Cv->at(I) + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : *Cv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+}
+
+// Ensure that 'const auto &' is used with containers of non-trivial types.
+void constness() {
+ int Sum = 0;
+ for (int I = 0, E = Constv.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Constv[I].X);
+ Sum += Constv[I].X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : Constv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+
+ for (int I = 0, E = Constv.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Constv.at(I).X);
+ Sum += Constv.at(I).X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : Constv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+
+ for (int I = 0, E = Pconstv->size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Pconstv->at(I).X);
+ Sum += Pconstv->at(I).X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : *Pconstv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+
+ // This test will fail if size() isn't called repeatedly, since it
+ // returns unsigned int, and 0 is deduced to be signed int.
+ // FIXME: Insert the necessary explicit conversion, or write out the types
+ // explicitly.
+ for (int I = 0; I < Pconstv->size(); ++I) {
+ printf("Fibonacci number is %d\n", (*Pconstv).at(I).X);
+ Sum += (*Pconstv)[I].X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : *Pconstv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+}
+
+void constRef(const dependent<int>& ConstVRef) {
+ int sum = 0;
+ // FIXME: This does not work with size_t (probably due to the implementation
+ // of dependent); make dependent work exactly like a std container type.
+ for (int I = 0; I < ConstVRef.size(); ++I) {
+ sum += ConstVRef[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : ConstVRef)
+ // CHECK-FIXES-NEXT: sum += I;
+
+ for (auto I = ConstVRef.begin(), E = ConstVRef.end(); I != E; ++I) {
+ sum += *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : ConstVRef)
+ // CHECK-FIXES-NEXT: sum += I;
+}
+
+// Check for loops that don't mention containers.
+void noContainer() {
+ for (auto I = 0; I < V.size(); ++I) {
+ }
+
+ for (auto I = 0; I < V.size(); ++I)
+ ;
+}
+
+struct NoBeginEnd {
+ unsigned size() const;
+ unsigned& operator[](int);
+ const unsigned& operator[](int) const;
+};
+
+struct NoConstBeginEnd {
+ NoConstBeginEnd();
+ unsigned size() const;
+ unsigned* begin();
+ unsigned* end();
+ unsigned& operator[](int);
+ const unsigned& operator[](int) const;
+};
+
+struct ConstBeginEnd {
+ ConstBeginEnd();
+ unsigned size() const;
+ unsigned* begin() const;
+ unsigned* end() const;
+ unsigned& operator[](int);
+ const unsigned& operator[](int) const;
+};
+
+// Shouldn't transform pseudo-array uses if the container doesn't provide
+// begin() and end() of the right const-ness.
+void NoBeginEndTest() {
+ NoBeginEnd NBE;
+ for (unsigned I = 0, E = NBE.size(); I < E; ++I)
+ printf("%d\n", NBE[I]);
+
+ const NoConstBeginEnd Const_NCBE;
+ for (unsigned I = 0, E = Const_NCBE.size(); I < E; ++I)
+ printf("%d\n", Const_NCBE[I]);
+
+ ConstBeginEnd CBE;
+ for (unsigned I = 0, E = CBE.size(); I < E; ++I)
+ printf("%d\n", CBE[I]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : CBE)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+
+ const ConstBeginEnd Const_CBE;
+ for (unsigned I = 0, E = Const_CBE.size(); I < E; ++I)
+ printf("%d\n", Const_CBE[I]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : Const_CBE)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+}
+
+struct DerefByValue {
+ DerefByValue();
+ struct iter { unsigned operator*(); };
+ unsigned size() const;
+ iter begin();
+ iter end();
+ unsigned operator[](int);
+};
+
+void derefByValueTest() {
+ DerefByValue DBV;
+ for (unsigned I = 0, E = DBV.size(); I < E; ++I) {
+ printf("%d\n", DBV[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : DBV)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+
+ for (unsigned I = 0, E = DBV.size(); I < E; ++I) {
+ auto f = [DBV, I]() {};
+ printf("%d\n", DBV[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : DBV)
+ // CHECK-FIXES-NEXT: auto f = [DBV, &I]() {};
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+}
+
+void fundamentalTypesTest() {
+ const int N = 10;
+ bool Bools[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Bools[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (bool Bool : Bools)
+
+ int Ints[N];
+ unsigned short int Shorts[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Shorts[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned short Short : Shorts)
+
+ signed long Longs[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Longs[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (long Long : Longs)
+
+ long long int LongLongs[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", LongLongs[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (long long LongLong : LongLongs)
+
+ char Chars[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Chars[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (char Char : Chars)
+
+ wchar_t WChars[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", WChars[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (wchar_t WChar : WChars)
+
+ float Floats[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Floats[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (float Float : Floats)
+
+ double Doubles[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Doubles[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (double Double : Doubles)
+}
+
+} // namespace PseudoArray
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-camelback.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-camelback.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-camelback.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-camelback.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-loop-convert.NamingStyle, value: 'camelBack'}]}" \
+// RUN: -- -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+const int n = 10;
+int arr[n];
+int nums[n];
+
+void naming() {
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", arr[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int i : arr)
+ // CHECK-FIXES-NEXT: printf("%d\n", i);
+
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int num : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", num);
+
+ int num = 0;
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i] + num);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int i : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", i + num);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-const.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-const.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-const.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-const.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,360 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t
+
+struct Str {
+ Str() = default;
+ Str(const Str &) = default;
+ void constMember(int) const;
+ void nonConstMember(int);
+ bool operator<(const Str &str) const; // const operator.
+ Str &operator=(const Str &str) = default; // non const operator.
+};
+
+// This class is non-trivially copyable because the copy-constructor and copy
+// assignment take non-const references.
+struct ModifiesRightSide {
+ ModifiesRightSide() = default;
+ ModifiesRightSide(ModifiesRightSide &) = default;
+ bool operator<(ModifiesRightSide &) const;
+ ModifiesRightSide &operator=(ModifiesRightSide &) = default;
+};
+
+template <typename T>
+void copyArg(T);
+
+template <typename T>
+void nonConstRefArg(T &);
+
+// If we define this as a template, the type is deduced to "T&",
+// and "const (T&) &" is the same as "T& &", and this collapses to "T&".
+void constRefArg(const Str &);
+void constRefArg(const ModifiesRightSide &);
+void constRefArg(const int &);
+
+void foo();
+
+const int N = 10;
+Str Array[N], OtherStr;
+ModifiesRightSide Right[N], OtherRight;
+int Ints[N], OtherInt;
+
+void memberFunctionsAndOperators() {
+ // Calling const member functions or operator is a const usage.
+ for (int I = 0; I < N; ++I) {
+ Array[I].constMember(0);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: I.constMember(0);
+
+ for (int I = 0; I < N; ++I) {
+ if (Array[I] < OtherStr)
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: if (I < OtherStr)
+ for (int I = 0; I < N; ++I) {
+ if (Right[I] < OtherRight)
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (const auto & I : Right)
+ // CHECK-FIXES-NEXT: if (I < OtherRight)
+
+ // Calling non-const member functions is not.
+ for (int I = 0; I < N; ++I) {
+ Array[I].nonConstMember(0);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: I.nonConstMember(0);
+
+ for (int I = 0; I < N; ++I) {
+ Array[I] = OtherStr;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: I = OtherStr;
+
+ for (int I = 0; I < N; ++I) {
+ Right[I] = OtherRight;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: I = OtherRight;
+}
+
+void usedAsParameterToFunctionOrOperator() {
+ // Copying is OK, as long as the copy constructor takes a const-reference.
+ for (int I = 0; I < N; ++I) {
+ copyArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: copyArg(I);
+
+ for (int I = 0; I < N; ++I) {
+ copyArg(Right[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: copyArg(I);
+
+ // Using as a const reference argument is allowed.
+ for (int I = 0; I < N; ++I) {
+ constRefArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: constRefArg(I);
+
+ for (int I = 0; I < N; ++I) {
+ if (OtherStr < Array[I])
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: if (OtherStr < I)
+
+ for (int I = 0; I < N; ++I) {
+ constRefArg(Right[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (const auto & I : Right)
+ // CHECK-FIXES-NEXT: constRefArg(I);
+
+ // Using as a non-const reference is not.
+ for (int I = 0; I < N; ++I) {
+ nonConstRefArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: nonConstRefArg(I);
+ for (int I = 0; I < N; ++I) {
+ nonConstRefArg(Right[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: nonConstRefArg(I);
+ for (int I = 0; I < N; ++I) {
+ if (OtherRight < Right[I])
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: if (OtherRight < I)
+}
+
+void primitiveTypes() {
+ // As argument to a function.
+ for (int I = 0; I < N; ++I) {
+ copyArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: copyArg(Int);
+ for (int I = 0; I < N; ++I) {
+ constRefArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: constRefArg(Int);
+ for (int I = 0; I < N; ++I) {
+ nonConstRefArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: nonConstRefArg(Int);
+
+ // Builtin operators.
+ // Comparisons.
+ for (int I = 0; I < N; ++I) {
+ if (Ints[I] < N)
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: if (Int < N)
+
+ for (int I = 0; I < N; ++I) {
+ if (N == Ints[I])
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: if (N == Int)
+
+ // Assignment.
+ for (int I = 0; I < N; ++I) {
+ Ints[I] = OtherInt;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: Int = OtherInt;
+
+ for (int I = 0; I < N; ++I) {
+ OtherInt = Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: OtherInt = Int;
+
+ for (int I = 0; I < N; ++I) {
+ OtherInt = Ints[I] = OtherInt;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: OtherInt = Int = OtherInt;
+
+ // Arithmetic operations.
+ for (int I = 0; I < N; ++I) {
+ OtherInt += Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: OtherInt += Int;
+
+ for (int I = 0; I < N; ++I) {
+ Ints[I] += Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: Int += Int;
+
+ for (int I = 0; I < N; ++I) {
+ int Res = 5 * (Ints[I] + 1) - Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: int Res = 5 * (Int + 1) - Int;
+}
+
+void takingReferences() {
+ // We do it twice to prevent the check from thinking that they are aliases.
+
+ // Class type.
+ for (int I = 0; I < N; ++I) {
+ Str &J = Array[I];
+ Str &K = Array[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: Str &J = I;
+ // CHECK-FIXES-NEXT: Str &K = I;
+ for (int I = 0; I < N; ++I) {
+ const Str &J = Array[I];
+ const Str &K = Array[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: const Str &J = I;
+ // CHECK-FIXES-NEXT: const Str &K = I;
+
+ // Primitive type.
+ for (int I = 0; I < N; ++I) {
+ int &J = Ints[I];
+ int &K = Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: int &J = Int;
+ // CHECK-FIXES-NEXT: int &K = Int;
+ for (int I = 0; I < N; ++I) {
+ const int &J = Ints[I];
+ const int &K = Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: const int &J = Int;
+ // CHECK-FIXES-NEXT: const int &K = Int;
+
+ // Aliases.
+ for (int I = 0; I < N; ++I) {
+ const Str &J = Array[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto J : Array)
+ for (int I = 0; I < N; ++I) {
+ Str &J = Array[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & J : Array)
+
+ for (int I = 0; I < N; ++I) {
+ const int &J = Ints[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int J : Ints)
+
+ for (int I = 0; I < N; ++I) {
+ int &J = Ints[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & J : Ints)
+}
+
+template <class T>
+struct vector {
+ unsigned size() const;
+ const T &operator[](int) const;
+ T &operator[](int);
+ T *begin();
+ T *end();
+ const T *begin() const;
+ const T *end() const;
+};
+
+// If the elements are already constant, we won't do any ImplicitCast to const.
+void testContainerOfConstIents() {
+ const int Ints[N]{};
+ for (int I = 0; I < N; ++I) {
+ OtherInt -= Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+
+ vector<const Str> Strs;
+ for (int I = 0; I < Strs.size(); ++I) {
+ Strs[I].constMember(0);
+ constRefArg(Strs[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto Str : Strs)
+}
+
+// When we are inside a const-qualified member functions, all the data members
+// are implicitly set as const. As before, there won't be any ImplicitCast to
+// const in their usages.
+class TestInsideConstFunction {
+ const static int N = 10;
+ int Ints[N];
+ Str Array[N];
+ vector<int> V;
+
+ void foo() const {
+ for (int I = 0; I < N; ++I) {
+ if (Ints[I])
+ copyArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+
+ for (int I = 0; I < N; ++I) {
+ Array[I].constMember(0);
+ constRefArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+
+ for (int I = 0; I < V.size(); ++I) {
+ if (V[I])
+ copyArg(V[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+ // CHECK-FIXES: for (int I : V)
+ }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-extra.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-extra.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-extra.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-extra.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,1085 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+namespace Dependency {
+
+void f() {
+ const int N = 6;
+ const int M = 8;
+ int Arr[N][M];
+
+ for (int I = 0; I < N; ++I) {
+ int A = 0;
+ int B = Arr[I][A];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: int A = 0;
+ // CHECK-FIXES-NEXT: int B = I[A];
+
+ for (int J = 0; J < M; ++J) {
+ int A = 0;
+ int B = Arr[A][J];
+ }
+}
+
+} // namespace Dependency
+
+namespace NamingAlias {
+
+const int N = 10;
+
+Val Arr[N];
+dependent<Val> V;
+dependent<Val> *Pv;
+Val &func(Val &);
+void sideEffect(int);
+
+void aliasing() {
+ // If the loop container is only used for a declaration of a temporary
+ // variable to hold each element, we can name the new variable for the
+ // converted range-based loop as the temporary variable's name.
+
+ // In the following case, "T" is used as a temporary variable to hold each
+ // element, and thus we consider the name "T" aliased to the loop.
+ // The extra blank braces are left as a placeholder for after the variable
+ // declaration is deleted.
+ for (int I = 0; I < N; ++I) {
+ Val &T = Arr[I];
+ {}
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & T : Arr)
+ // CHECK-FIXES-NOT: Val &{{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ // The container was not only used to initialize a temporary loop variable for
+ // the container's elements, so we do not alias the new loop variable.
+ for (int I = 0; I < N; ++I) {
+ Val &T = Arr[I];
+ int Y = T.X;
+ int Z = Arr[I].X + T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: Val &T = I;
+ // CHECK-FIXES-NEXT: int Y = T.X;
+ // CHECK-FIXES-NEXT: int Z = I.X + T.X;
+
+ for (int I = 0; I < N; ++I) {
+ Val T = Arr[I];
+ int Y = T.X;
+ int Z = Arr[I].X + T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: Val T = I;
+ // CHECK-FIXES-NEXT: int Y = T.X;
+ // CHECK-FIXES-NEXT: int Z = I.X + T.X;
+
+ // The same for pseudo-arrays like std::vector<T> (or here dependent<Val>)
+ // which provide a subscript operator[].
+ for (int I = 0; I < V.size(); ++I) {
+ Val &T = V[I];
+ {}
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & T : V)
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ // The same with a call to at()
+ for (int I = 0; I < Pv->size(); ++I) {
+ Val &T = Pv->at(I);
+ {}
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & T : *Pv)
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ for (int I = 0; I < N; ++I) {
+ Val &T = func(Arr[I]);
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: Val &T = func(I);
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ int IntArr[N];
+ for (unsigned I = 0; I < N; ++I) {
+ if (int Alias = IntArr[I]) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: if (Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ while (int Alias = IntArr[I]) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: while (Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ switch (int Alias = IntArr[I]) {
+ default:
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: switch (Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ for (int Alias = IntArr[I]; Alias < N; ++Alias) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: for (; Alias < N; ++Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ for (unsigned J = 0; int Alias = IntArr[I]; ++J) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: for (unsigned J = 0; Alias; ++J)
+
+ struct IntRef { IntRef(); IntRef(const int& i); operator int*(); };
+ for (int I = 0; I < N; ++I) {
+ IntRef Int(IntArr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : IntArr)
+ // CHECK-FIXES-NEXT: IntRef Int(I);
+
+ int *PtrArr[N];
+ for (unsigned I = 0; I < N; ++I) {
+ const int* const P = PtrArr[I];
+ printf("%d\n", *P);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto P : PtrArr)
+ // CHECK-FIXES-NEXT: printf("%d\n", *P);
+
+ IntRef Refs[N];
+ for (unsigned I = 0; I < N; ++I) {
+ int *P = Refs[I];
+ printf("%d\n", *P);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Ref : Refs)
+ // CHECK-FIXES-NEXT: int *P = Ref;
+ // CHECK-FIXES-NEXT: printf("%d\n", *P);
+
+ // Ensure that removing the alias doesn't leave empty lines behind.
+ for (int I = 0; I < N; ++I) {
+ auto &X = IntArr[I];
+ X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & X : IntArr) {
+ // CHECK-FIXES-NEXT: {{^ X = 0;$}}
+ // CHECK-FIXES-NEXT: {{^ }$}}
+}
+
+void refs_and_vals() {
+ // The following tests check that the transform correctly preserves the
+ // reference or value qualifiers of the aliased variable. That is, if the
+ // variable was declared as a value, the loop variable will be declared as a
+ // value and vice versa for references.
+
+ S Ss;
+ const S S_const = Ss;
+
+ for (S::const_iterator It = S_const.begin(); It != S_const.end(); ++It) {
+ MutableVal Alias = *It;
+ {}
+ Alias.X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Alias : S_const)
+ // CHECK-FIXES-NOT: MutableVal {{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: Alias.X = 0;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ MutableVal Alias = *It;
+ {}
+ Alias.X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Alias : Ss)
+ // CHECK-FIXES-NOT: MutableVal {{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: Alias.X = 0;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ MutableVal &Alias = *It;
+ {}
+ Alias.X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Alias : Ss)
+ // CHECK-FIXES-NOT: MutableVal &{{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: Alias.X = 0;
+
+ dependent<int> Dep, Other;
+ for (dependent<int>::iterator It = Dep.begin(), E = Dep.end(); It != E; ++It) {
+ printf("%d\n", *It);
+ const int& Idx = Other[0];
+ unsigned Othersize = Other.size();
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Dep)
+ // CHECK-FIXES-NEXT: printf("%d\n", It);
+ // CHECK-FIXES-NEXT: const int& Idx = Other[0];
+ // CHECK-FIXES-NEXT: unsigned Othersize = Other.size();
+
+ for (int i = 0; i < Other.size(); ++i) {
+ Other.at(i);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & i : Other)
+ // CHECK-FIXES: i;
+
+ for (int I = 0, E = Dep.size(); I != E; ++I) {
+ int Idx = Other.at(I);
+ Other.at(I, I); // Should not trigger assert failure.
+ }
+}
+
+struct MemberNaming {
+ const static int N = 10;
+ int Ints[N], Ints_[N];
+ dependent<int> DInts;
+ void loops() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints_[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints_)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+
+ for (int I = 0; I < DInts.size(); ++I) {
+ printf("%d\n", DInts[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int DInt : DInts)
+ // CHECK-FIXES-NEXT: printf("%d\n", DInt);
+ }
+
+ void outOfLine();
+};
+void MemberNaming::outOfLine() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints_[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints_)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+}
+
+} // namespace NamingAlias
+
+namespace NamingConlict {
+
+#define MAX(a, b) (a > b) ? a : b
+#define DEF 5
+
+const int N = 10;
+int Nums[N];
+int Sum = 0;
+
+namespace ns {
+struct St {
+ int X;
+};
+}
+
+void sameNames() {
+ int Num = 0;
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number is %d\n", Nums[I]);
+ Sum += Nums[I] + 2 + Num;
+ (void)Nums[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Nums)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2 + Num;
+ // CHECK-FIXES-NEXT: (void)I;
+
+ int Elem = 0;
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number is %d\n", Nums[I]);
+ Sum += Nums[I] + 2 + Num + Elem;
+ (void)Nums[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Nums)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2 + Num + Elem;
+ // CHECK-FIXES-NEXT: (void)I;
+}
+
+void oldIndexConflict() {
+ for (int Num = 0; Num < N; ++Num) {
+ printf("Num: %d\n", Nums[Num]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Num : Nums)
+ // CHECK-FIXES-NEXT: printf("Num: %d\n", Num);
+
+ S Things;
+ for (S::iterator Thing = Things.begin(), End = Things.end(); Thing != End; ++Thing) {
+ printf("Thing: %d %d\n", Thing->X, (*Thing).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Thing : Things)
+ // CHECK-FIXES-NEXT: printf("Thing: %d %d\n", Thing.X, Thing.X);
+}
+
+void macroConflict() {
+ S MAXs;
+ for (S::iterator It = MAXs.begin(), E = MAXs.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ printf("Max of 3 and 5: %d\n", MAX(3, 5));
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : MAXs)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+ // CHECK-FIXES-NEXT: printf("Max of 3 and 5: %d\n", MAX(3, 5));
+
+ for (S::const_iterator It = MAXs.begin(), E = MAXs.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ printf("Max of 3 and 5: %d\n", MAX(3, 5));
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : MAXs)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+ // CHECK-FIXES-NEXT: printf("Max of 3 and 5: %d\n", MAX(3, 5));
+
+ T DEFs;
+ for (T::iterator It = DEFs.begin(), E = DEFs.end(); It != E; ++It) {
+ if (*It == DEF) {
+ printf("I found %d\n", *It);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : DEFs)
+ // CHECK-FIXES-NEXT: if (It == DEF)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+}
+
+void keywordConflict() {
+ T ints;
+ for (T::iterator It = ints.begin(), E = ints.end(); It != E; ++It) {
+ *It = 5;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : ints)
+ // CHECK-FIXES-NEXT: It = 5;
+
+ U __FUNCTION__s;
+ for (U::iterator It = __FUNCTION__s.begin(), E = __FUNCTION__s.end();
+ It != E; ++It) {
+ int __FUNCTION__s_It = (*It).X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : __FUNCTION__s)
+ // CHECK-FIXES-NEXT: int __FUNCTION__s_It = It.X + 2;
+}
+
+void typeConflict() {
+ T Vals;
+ // Using the name "Val", although it is the name of an existing struct, is
+ // safe in this loop since it will only exist within this scope.
+ for (T::iterator It = Vals.begin(), E = Vals.end(); It != E; ++It)
+ (void) *It;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & Val : Vals)
+
+ // We cannot use the name "Val" in this loop since there is a reference to
+ // it in the body of the loop.
+ for (T::iterator It = Vals.begin(), E = Vals.end(); It != E; ++It) {
+ *It = sizeof(Val);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Vals)
+ // CHECK-FIXES-NEXT: It = sizeof(Val);
+
+ typedef struct Val TD;
+ U TDs;
+ // Naming the variable "TD" within this loop is safe because the typedef
+ // was never used within the loop.
+ for (U::iterator It = TDs.begin(), E = TDs.end(); It != E; ++It)
+ (void) *It;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & TD : TDs)
+
+ // "TD" cannot be used in this loop since the typedef is being used.
+ for (U::iterator It = TDs.begin(), E = TDs.end(); It != E; ++It) {
+ TD V;
+ V.X = 5;
+ (void) *It;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : TDs)
+ // CHECK-FIXES-NEXT: TD V;
+ // CHECK-FIXES-NEXT: V.X = 5;
+
+ using ns::St;
+ T Sts;
+ for (T::iterator It = Sts.begin(), E = Sts.end(); It != E; ++It) {
+ *It = sizeof(St);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Sts)
+ // CHECK-FIXES-NEXT: It = sizeof(St);
+}
+
+} // namespace NamingConflict
+
+namespace FreeBeginEnd {
+
+// FIXME: Loop Convert should detect free begin()/end() functions.
+
+struct MyArray {
+ unsigned size();
+};
+
+template <typename T>
+struct MyContainer {
+};
+
+int *begin(const MyArray &Arr);
+int *end(const MyArray &Arr);
+
+template <typename T>
+T *begin(const MyContainer<T> &C);
+template <typename T>
+T *end(const MyContainer<T> &C);
+
+// The Loop Convert Transform doesn't detect free functions begin()/end() and
+// so fails to transform these cases which it should.
+void f() {
+ MyArray Arr;
+ for (unsigned I = 0, E = Arr.size(); I < E; ++I) {
+ }
+
+ MyContainer<int> C;
+ for (int *I = begin(C), *E = end(C); I != E; ++I) {
+ }
+}
+
+} // namespace FreeBeginEnd
+
+namespace Nesting {
+
+void g(S::iterator It);
+void const_g(S::const_iterator It);
+class Foo {
+ public:
+ void g(S::iterator It);
+ void const_g(S::const_iterator It);
+};
+
+void f() {
+ const int N = 10;
+ const int M = 15;
+ Val Arr[N];
+ for (int I = 0; I < N; ++I) {
+ for (int J = 0; J < N; ++J) {
+ int K = Arr[I].X + Arr[J].X;
+ // The repeat is there to allow FileCheck to make sure the two variable
+ // names aren't the same.
+ int L = Arr[I].X + Arr[J].X;
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-8]]:3: warning: use range-based for loop instead
+ // CHECK-MESSAGES: :[[@LINE-8]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: for (auto & J : Arr)
+ // CHECK-FIXES-NEXT: int K = I.X + J.X;
+ // CHECK-FIXES-NOT: int L = I.X + I.X;
+
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. FIXME: update this test when that changes.
+ Val Nest[N][M];
+ for (int I = 0; I < N; ++I) {
+ for (int J = 0; J < M; ++J) {
+ printf("Got item %d", Nest[I][J].X);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Nest)
+ // CHECK-FIXES-NEXT: for (int J = 0; J < M; ++J)
+ // CHECK-FIXES-NEXT: printf("Got item %d", I[J].X);
+
+ // Note that the order of M and N are switched for this test.
+ for (int J = 0; J < M; ++J) {
+ for (int I = 0; I < N; ++I) {
+ printf("Got item %d", Nest[I][J].X);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES-NOT: for (auto & {{[a-zA-Z_]+}} : Nest[I])
+ // CHECK-FIXES: for (int J = 0; J < M; ++J)
+ // CHECK-FIXES-NEXT: for (auto & I : Nest)
+ // CHECK-FIXES-NEXT: printf("Got item %d", I[J].X);
+
+ // The inner loop is also convertible.
+ Nested<T> NestT;
+ for (Nested<T>::iterator I = NestT.begin(), E = NestT.end(); I != E; ++I) {
+ for (T::iterator TI = (*I).begin(), TE = (*I).end(); TI != TE; ++TI) {
+ printf("%d", *TI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : NestT)
+ // CHECK-FIXES-NEXT: for (T::iterator TI = I.begin(), TE = I.end(); TI != TE; ++TI)
+ // CHECK-FIXES-NEXT: printf("%d", *TI);
+
+ // The inner loop is also convertible.
+ Nested<S> NestS;
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ for (S::const_iterator SI = (*I).begin(), SE = (*I).end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto I : NestS)
+ // CHECK-FIXES-NEXT: for (S::const_iterator SI = I.begin(), SE = I.end(); SI != SE; ++SI)
+ // CHECK-FIXES-NEXT: printf("%d", *SI);
+
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ const S &Ss = *I;
+ for (S::const_iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ const_g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Ss : NestS)
+
+ for (Nested<S>::iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ S &Ss = *I;
+ for (S::iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Ss : NestS)
+
+ Foo foo;
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ const S &Ss = *I;
+ for (S::const_iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ foo.const_g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Ss : NestS)
+
+ for (Nested<S>::iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ S &Ss = *I;
+ for (S::iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ foo.g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Ss : NestS)
+
+}
+
+} // namespace Nesting
+
+namespace SingleIterator {
+
+void complexContainer() {
+ X Exes[5];
+ int Index = 0;
+
+ for (S::iterator I = Exes[Index].getS().begin(), E = Exes[Index].getS().end(); I != E; ++I) {
+ MutableVal K = *I;
+ MutableVal J = *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Exes[Index].getS())
+ // CHECK-FIXES-NEXT: MutableVal K = I;
+ // CHECK-FIXES-NEXT: MutableVal J = I;
+}
+
+void f() {
+ /// begin()/end() - based for loops here:
+ T Tt;
+ for (T::iterator It = Tt.begin(); It != Tt.end(); ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Tt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ T *Pt;
+ for (T::iterator It = Pt->begin(); It != Pt->end(); ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : *Pt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ S Ss;
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::iterator It = Ps->begin(); It != Ps->end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ It->X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ (*It).X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ It->nonConstFun(4, 5);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.nonConstFun(4, 5);
+
+ U Uu;
+ for (U::iterator It = Uu.begin(); It != Uu.end(); ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (U::iterator It = Uu.begin(); It != Uu.end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ U::iterator A;
+ for (U::iterator I = Uu.begin(); I != Uu.end(); ++I)
+ int K = A->X + I->X;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Uu)
+ // CHECK-FIXES-NEXT: int K = A->X + I.X;
+
+ dependent<int> V;
+ for (dependent<int>::iterator It = V.begin();
+ It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ for (dependent<int>::iterator It(V.begin());
+ It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ doublyDependent<int, int> intmap;
+ for (doublyDependent<int, int>::iterator It = intmap.begin();
+ It != intmap.end(); ++It) {
+ printf("intmap[%d] = %d", It->first, It->second);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : intmap)
+ // CHECK-FIXES-NEXT: printf("intmap[%d] = %d", It.first, It.second);
+}
+
+void different_type() {
+ // Tests to verify the proper use of auto where the init variable type and the
+ // initializer type differ or are mostly the same except for const qualifiers.
+
+ // Ss.begin() returns a type 'iterator' which is just a non-const pointer and
+ // differs from const_iterator only on the const qualification.
+ S Ss;
+ for (S::const_iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::const_iterator It = Ps->begin(); It != Ps->end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ dependent<int> V;
+ for (dependent<int>::const_iterator It = V.begin(); It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ for (dependent<int>::const_iterator It(V.begin()); It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+}
+
+} // namespace SingleIterator
+
+
+namespace Macros {
+
+#define TWO_PARAM(x, y) if (x == y) {}
+#define THREE_PARAM(x, y, z) if (x == y) {z;}
+
+const int N = 10;
+int Arr[N];
+
+void messing_with_macros() {
+ for (int I = 0; I < N; ++I) {
+ printf("Value: %d\n", Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: printf("Value: %d\n", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("Value: %d\n", CONT Arr[I]);
+ }
+
+ // Multiple macro arguments.
+ for (int I = 0; I < N; ++I) {
+ TWO_PARAM(Arr[I], Arr[I]);
+ THREE_PARAM(Arr[I], Arr[I], Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: TWO_PARAM(I, I);
+ // CHECK-FIXES-NEXT: THREE_PARAM(I, I, I);
+}
+
+} // namespace Macros
+
+namespace Templates {
+
+template <class Container>
+void set_union(Container &container) {
+ for (typename Container::const_iterator SI = container.begin(),
+ SE = container.end(); SI != SE; ++SI) {
+ (void) *SI;
+ }
+
+ S Ss;
+ for (S::iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI)
+ (void) *SI;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & SI : Ss)
+}
+
+void template_instantiation() {
+ S Ss;
+ set_union(Ss);
+}
+
+} // namespace Templates
+
+namespace Lambdas {
+
+void capturesIndex() {
+ const int N = 10;
+ int Arr[N];
+ // FIXME: the next four loops could be convertible, if the capture list is
+ // also changed.
+
+ for (int I = 0; I < N; ++I)
+ auto F1 = [Arr, I]() { int R1 = Arr[I] + 1; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F1 = [Arr, &I]() { int R1 = I + 1; };
+
+ for (int I = 0; I < N; ++I)
+ auto F2 = [Arr, &I]() { int R2 = Arr[I] + 3; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F2 = [Arr, &I]() { int R2 = I + 3; };
+
+ // FIXME: alias don't work if the index is captured.
+ // Alias declared inside lambda (by value).
+ for (int I = 0; I < N; ++I)
+ auto F3 = [&Arr, I]() { int R3 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F3 = [&Arr, &I]() { int R3 = I; };
+
+
+ for (int I = 0; I < N; ++I)
+ auto F4 = [&Arr, &I]() { int R4 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F4 = [&Arr, &I]() { int R4 = I; };
+
+ // Alias declared inside lambda (by reference).
+ for (int I = 0; I < N; ++I)
+ auto F5 = [&Arr, I]() { int &R5 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: auto F5 = [&Arr, &I]() { int &R5 = I; };
+
+
+ for (int I = 0; I < N; ++I)
+ auto F6 = [&Arr, &I]() { int &R6 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: auto F6 = [&Arr, &I]() { int &R6 = I; };
+
+ for (int I = 0; I < N; ++I) {
+ auto F = [Arr, I](int k) {
+ printf("%d\n", Arr[I] + k);
+ };
+ F(Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F = [Arr, &I](int k)
+ // CHECK-FIXES-NEXT: printf("%d\n", I + k);
+ // CHECK-FIXES: F(I);
+}
+
+void implicitCapture() {
+ const int N = 10;
+ int Arr[N];
+ // Index is used, not convertible.
+ for (int I = 0; I < N; ++I) {
+ auto G1 = [&]() {
+ int R = Arr[I];
+ int J = I;
+ };
+ }
+
+ for (int I = 0; I < N; ++I) {
+ auto G2 = [=]() {
+ int R = Arr[I];
+ int J = I;
+ };
+ }
+
+ // Convertible.
+ for (int I = 0; I < N; ++I) {
+ auto G3 = [&]() {
+ int R3 = Arr[I];
+ int J3 = Arr[I] + R3;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto G3 = [&]()
+ // CHECK-FIXES-NEXT: int R3 = I;
+ // CHECK-FIXES-NEXT: int J3 = I + R3;
+
+ for (int I = 0; I < N; ++I) {
+ auto G4 = [=]() {
+ int R4 = Arr[I] + 5;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto G4 = [=]()
+ // CHECK-FIXES-NEXT: int R4 = I + 5;
+
+ // Alias by value.
+ for (int I = 0; I < N; ++I) {
+ auto G5 = [&]() {
+ int R5 = Arr[I];
+ int J5 = 8 + R5;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int R5 : Arr)
+ // CHECK-FIXES-NEXT: auto G5 = [&]()
+ // CHECK-FIXES-NEXT: int J5 = 8 + R5;
+
+ // Alias by reference.
+ for (int I = 0; I < N; ++I) {
+ auto G6 = [&]() {
+ int &R6 = Arr[I];
+ int J6 = -1 + R6;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & R6 : Arr)
+ // CHECK-FIXES-NEXT: auto G6 = [&]()
+ // CHECK-FIXES-NEXT: int J6 = -1 + R6;
+}
+
+void iterators() {
+ dependent<int> Dep;
+
+ for (dependent<int>::iterator I = Dep.begin(), E = Dep.end(); I != E; ++I)
+ auto H1 = [&I]() { int R = *I; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Dep)
+ // CHECK-FIXES-NEXT: auto H1 = [&I]() { int R = I; };
+
+ for (dependent<int>::iterator I = Dep.begin(), E = Dep.end(); I != E; ++I)
+ auto H2 = [&]() { int R = *I + 2; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Dep)
+ // CHECK-FIXES-NEXT: auto H2 = [&]() { int R = I + 2; };
+
+ for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
+ I != E; ++I)
+ auto H3 = [I]() { int R = *I; };
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Dep)
+ // CHECK-FIXES-NEXT: auto H3 = [&I]() { int R = I; };
+
+ for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
+ I != E; ++I)
+ auto H4 = [&]() { int R = *I + 1; };
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Dep)
+ // CHECK-FIXES-NEXT: auto H4 = [&]() { int R = I + 1; };
+
+ for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
+ I != E; ++I)
+ auto H5 = [=]() { int R = *I; };
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int R : Dep)
+ // CHECK-FIXES-NEXT: auto H5 = [=]() { };
+}
+
+void captureByValue() {
+ // When the index is captured by value, we should replace this by a capture
+ // by reference. This avoids extra copies.
+ // FIXME: this could change semantics on array or pseudoarray loops if the
+ // container is captured by copy.
+ const int N = 10;
+ int Arr[N];
+ dependent<int> Dep;
+
+ for (int I = 0; I < N; ++I) {
+ auto C1 = [&Arr, I]() { if (Arr[I] == 1); };
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto C1 = [&Arr, &I]() { if (I == 1); };
+
+ for (unsigned I = 0; I < Dep.size(); ++I) {
+ auto C2 = [&Dep, I]() { if (Dep[I] == 2); };
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Dep)
+ // CHECK-FIXES-NEXT: auto C2 = [&Dep, &I]() { if (I == 2); };
+}
+
+} // namespace Lambdas
+
+namespace InitLists {
+
+struct D { int Ii; };
+struct E { D Dd; };
+int g(int B);
+
+void f() {
+ const unsigned N = 3;
+ int Array[N];
+
+ // Subtrees of InitListExpr are visited twice. Test that we do not do repeated
+ // replacements.
+ for (unsigned I = 0; I < N; ++I) {
+ int A{ Array[I] };
+ int B{ g(Array[I]) };
+ int C{ g( { Array[I] } ) };
+ D Dd{ { g( { Array[I] } ) } };
+ E Ee{ { { g( { Array[I] } ) } } };
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Array)
+ // CHECK-FIXES-NEXT: int A{ I };
+ // CHECK-FIXES-NEXT: int B{ g(I) };
+ // CHECK-FIXES-NEXT: int C{ g( { I } ) };
+ // CHECK-FIXES-NEXT: D Dd{ { g( { I } ) } };
+ // CHECK-FIXES-NEXT: E Ee{ { { g( { I } ) } } };
+}
+
+} // namespace InitLists
+
+void bug28341() {
+ char v[5];
+ for(int i = 0; i < 5; ++i) {
+ unsigned char value = v[i];
+ if (value > 127)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for(unsigned char value : v)
+ // CHECK-FIXES-NEXT: if (value > 127)
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-lowercase.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-lowercase.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-lowercase.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-lowercase.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-loop-convert.NamingStyle, value: 'lower_case'}]}" \
+// RUN: -- -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+const int n = 10;
+int arr[n];
+int nums[n];
+int nums_[n];
+
+void naming() {
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", arr[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int i : arr)
+ // CHECK-FIXES-NEXT: printf("%d\n", i);
+
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int num : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", num);
+
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums_[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int num : nums_)
+ // CHECK-FIXES-NEXT: printf("%d\n", num);
+
+ int num = 0;
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i] + num);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int i : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", i + num);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-negative.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-negative.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-negative.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-negative.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,485 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+// CHECK-FIXES-NOT: for ({{.*[^:]:[^:].*}})
+// CHECK-MESSAGES-NOT: modernize-loop-convert
+
+namespace Negative {
+
+const int N = 6;
+int Arr[N] = {1, 2, 3, 4, 5, 6};
+int (*pArr)[N] = &Arr;
+int Sum = 0;
+
+// Checks for the Index start and end:
+void IndexStartAndEnd() {
+ for (int I = 0; I < N + 1; ++I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N - 1; ++I)
+ Sum += Arr[I];
+
+ for (int I = 1; I < N; ++I)
+ Sum += Arr[I];
+
+ for (int I = 1; I < N; ++I)
+ Sum += Arr[I];
+
+ for (int I = 0;; ++I)
+ Sum += (*pArr)[I];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int I = 0; I < N; --I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N; I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N;)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N; I += 2)
+ Sum++;
+}
+
+// Checks to make sure that the Index isn't used outside of the array:
+void IndexUse() {
+ for (int I = 0; I < N; ++I)
+ Arr[I] += 1 + I;
+}
+
+// Check for loops that don't mention arrays
+void noArray() {
+ for (int I = 0; I < N; ++I)
+ Sum += I;
+
+ for (int I = 0; I < N; ++I) {
+ }
+
+ for (int I = 0; I < N; ++I)
+ ;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int BadIndex;
+ for (int I = 0; BadIndex < N; ++I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N; ++BadIndex)
+ Sum += Arr[I];
+
+ for (int I = 0; BadIndex < N; ++BadIndex)
+ Sum += Arr[I];
+
+ for (int I = 0; BadIndex < N; ++BadIndex)
+ Sum += Arr[BadIndex];
+}
+
+// Checks for multiple arrays Indexed.
+void multipleArrays() {
+ int BadArr[N];
+
+ for (int I = 0; I < N; ++I)
+ Sum += Arr[I] + BadArr[I];
+
+ for (int I = 0; I < N; ++I) {
+ int K = BadArr[I];
+ Sum += Arr[I] + K;
+ }
+}
+
+}
+
+namespace NegativeIterator {
+
+S Ss;
+T Tt;
+U Tu;
+
+struct BadBeginEnd : T {
+ iterator notBegin();
+ iterator notEnd();
+};
+
+void notBeginOrEnd() {
+ BadBeginEnd Bad;
+ for (T::iterator I = Bad.notBegin(), E = Bad.end(); I != E; ++I)
+ int K = *I;
+
+ for (T::iterator I = Bad.begin(), E = Bad.notEnd(); I != E; ++I)
+ int K = *I;
+}
+
+void badLoopShapes() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(), F = E; I != E; ++I)
+ int K = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E;)
+ int K = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end();; ++I)
+ int K = *I;
+
+ T::iterator OutsideI;
+ T::iterator OutsideE;
+
+ for (; OutsideI != OutsideE; ++OutsideI)
+ int K = *OutsideI;
+}
+
+void iteratorArrayMix() {
+ int Lower;
+ const int N = 6;
+ for (T::iterator I = Tt.begin(), E = Tt.end(); Lower < N; ++I)
+ int K = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); Lower < N; ++Lower)
+ int K = *I;
+}
+
+struct ExtraConstructor : T::iterator {
+ ExtraConstructor(T::iterator, int);
+ explicit ExtraConstructor(T::iterator);
+};
+
+void badConstructor() {
+ for (T::iterator I = ExtraConstructor(Tt.begin(), 0), E = Tt.end();
+ I != E; ++I)
+ int K = *I;
+ for (T::iterator I = ExtraConstructor(Tt.begin()), E = Tt.end(); I != E; ++I)
+ int K = *I;
+}
+
+void foo(S::iterator It) {}
+class Foo {public: void bar(S::iterator It); };
+Foo Fo;
+
+void iteratorUsed() {
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ foo(I);
+
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ Fo.bar(I);
+
+ S::iterator Ret;
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ Ret = I;
+}
+
+void iteratorMemberUsed() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ I.X = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ int K = I.X + *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ int K = E.X + *I;
+}
+
+void iteratorMethodCalled() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ I.insert(3);
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ if (I != I)
+ int K = 3;
+}
+
+void iteratorOperatorCalled() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ int K = *(++I);
+
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ MutableVal K = *(++I);
+}
+
+void differentContainers() {
+ T Other;
+ for (T::iterator I = Tt.begin(), E = Other.end(); I != E; ++I)
+ int K = *I;
+
+ for (T::iterator I = Other.begin(), E = Tt.end(); I != E; ++I)
+ int K = *I;
+
+ S OtherS;
+ for (S::iterator I = Ss.begin(), E = OtherS.end(); I != E; ++I)
+ MutableVal K = *I;
+
+ for (S::iterator I = OtherS.begin(), E = Ss.end(); I != E; ++I)
+ MutableVal K = *I;
+}
+
+void wrongIterators() {
+ T::iterator Other;
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != Other; ++I)
+ int K = *I;
+}
+
+struct EvilArrow : U {
+ // Please, no one ever write code like this.
+ U *operator->();
+};
+
+void differentMemberAccessTypes() {
+ EvilArrow A;
+ for (EvilArrow::iterator I = A.begin(), E = A->end(); I != E; ++I)
+ Val K = *I;
+ for (EvilArrow::iterator I = A->begin(), E = A.end(); I != E; ++I)
+ Val K = *I;
+}
+
+void f(const T::iterator &It, int);
+void f(const T &It, int);
+void g(T &It, int);
+
+void iteratorPassedToFunction() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ f(I, *I);
+}
+
+// FIXME: These tests can be removed if this tool ever does enough analysis to
+// decide that this is a safe transformation. Until then, we don't want it
+// applied.
+void iteratorDefinedOutside() {
+ T::iterator TheEnd = Tt.end();
+ for (T::iterator I = Tt.begin(); I != TheEnd; ++I)
+ int K = *I;
+
+ T::iterator TheBegin = Tt.begin();
+ for (T::iterator E = Tt.end(); TheBegin != E; ++TheBegin)
+ int K = *TheBegin;
+}
+
+} // namespace NegativeIterator
+
+namespace NegativePseudoArray {
+
+const int N = 6;
+dependent<int> V;
+dependent<int> *Pv;
+
+int Sum = 0;
+
+// Checks for the Index start and end:
+void IndexStartAndEnd() {
+ for (int I = 0; I < V.size() + 1; ++I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size() - 1; ++I)
+ Sum += V[I];
+
+ for (int I = 1; I < V.size(); ++I)
+ Sum += V[I];
+
+ for (int I = 1; I < V.size(); ++I)
+ Sum += V[I];
+
+ for (int I = 0;; ++I)
+ Sum += (*Pv)[I];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int I = 0; I < V.size(); --I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size(); I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size();)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size(); I += 2)
+ Sum++;
+}
+
+// Checks to make sure that the Index isn't used outside of the container:
+void IndexUse() {
+ for (int I = 0; I < V.size(); ++I)
+ V[I] += 1 + I;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int BadIndex;
+ for (int I = 0; BadIndex < V.size(); ++I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size(); ++BadIndex)
+ Sum += V[I];
+
+ for (int I = 0; BadIndex < V.size(); ++BadIndex)
+ Sum += V[I];
+
+ for (int I = 0; BadIndex < V.size(); ++BadIndex)
+ Sum += V[BadIndex];
+}
+
+// Checks for an array Indexed in addition to the container.
+void multipleArrays() {
+ int BadArr[N];
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += V[I] + BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += K + 2;
+ }
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += V[I] + K;
+ }
+}
+
+// Checks for multiple containers being Indexed container.
+void multipleContainers() {
+ dependent<int> BadArr;
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += V[I] + BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += K + 2;
+ }
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += V[I] + K;
+ }
+}
+
+// Check to make sure that dereferenced pointers-to-containers behave nicely.
+void derefContainer() {
+ // Note the dependent<T>::operator*() returns another dependent<T>.
+ // This test makes sure that we don't allow an arbitrary number of *'s.
+ for (int I = 0; I < Pv->size(); ++I)
+ Sum += (**Pv).at(I);
+
+ for (int I = 0; I < Pv->size(); ++I)
+ Sum += (**Pv)[I];
+}
+
+void wrongEnd() {
+ int Bad;
+ for (int I = 0, E = V.size(); I < Bad; ++I)
+ Sum += V[I];
+}
+
+// Checks to see that non-const member functions are not called on the container
+// object.
+// These could be conceivably allowed with a lower required confidence level.
+void memberFunctionCalled() {
+ for (int I = 0; I < V.size(); ++I) {
+ Sum += V[I];
+ V.foo();
+ }
+
+ for (int I = 0; I < V.size(); ++I) {
+ Sum += V[I];
+ dependent<int>::iterator It = V.begin();
+ }
+}
+
+} // namespace NegativePseudoArray
+
+namespace NegativeMultiEndCall {
+
+S Ss;
+T Tt;
+U Uu;
+
+void f(X);
+void f(S);
+void f(T);
+
+void complexContainer() {
+ X Xx;
+ for (S::iterator I = Xx.Ss.begin(), E = Xx.Ss.end(); I != E; ++I) {
+ f(Xx);
+ MutableVal K = *I;
+ }
+
+ for (T::iterator I = Xx.Tt.begin(), E = Xx.Tt.end(); I != E; ++I) {
+ f(Xx);
+ int K = *I;
+ }
+
+ for (S::iterator I = Xx.Ss.begin(), E = Xx.Ss.end(); I != E; ++I) {
+ f(Xx.Ss);
+ MutableVal K = *I;
+ }
+
+ for (T::iterator I = Xx.Tt.begin(), E = Xx.Tt.end(); I != E; ++I) {
+ f(Xx.Tt);
+ int K = *I;
+ }
+
+ for (S::iterator I = Xx.getS().begin(), E = Xx.getS().end(); I != E; ++I) {
+ f(Xx.getS());
+ MutableVal K = *I;
+ }
+
+ X Exes[5];
+ int Index = 0;
+
+ for (S::iterator I = Exes[Index].getS().begin(),
+ E = Exes[Index].getS().end();
+ I != E; ++I) {
+ Index++;
+ MutableVal K = *I;
+ }
+}
+
+} // namespace NegativeMultiEndCall
+
+namespace NoUsages {
+
+const int N = 6;
+int Arr[N] = {1, 2, 3, 4, 5, 6};
+S Ss;
+dependent<int> V;
+int Count = 0;
+
+void foo();
+
+void f() {
+ for (int I = 0; I < N; ++I) {}
+ for (int I = 0; I < N; ++I)
+ printf("Hello world\n");
+ for (int I = 0; I < N; ++I)
+ ++Count;
+ for (int I = 0; I < N; ++I)
+ foo();
+
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I) {}
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ printf("Hello world\n");
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ ++Count;
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ foo();
+
+ for (int I = 0; I < V.size(); ++I) {}
+ for (int I = 0; I < V.size(); ++I)
+ printf("Hello world\n");
+ for (int I = 0; I < V.size(); ++I)
+ ++Count;
+ for (int I = 0; I < V.size(); ++I)
+ foo();
+}
+
+} // namespace NoUsages
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-uppercase.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-uppercase.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-uppercase.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert-uppercase.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-loop-convert.NamingStyle, value: 'UPPER_CASE'}]}" \
+// RUN: -- -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+const int N = 10;
+int ARR[N];
+int NUMS[N];
+int NUMS_[N];
+
+void naming() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", ARR[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int I : ARR)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", NUMS[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int NUM : NUMS)
+ // CHECK-FIXES-NEXT: printf("%d\n", NUM);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", NUMS_[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int NUM : NUMS_)
+ // CHECK-FIXES-NEXT: printf("%d\n", NUM);
+
+ int NUM = 0;
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", NUMS[I] + NUM);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : NUMS)
+ // CHECK-FIXES-NEXT: printf("%d\n", I + NUM);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-loop-convert.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,12 @@
+// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -- -std=c11 | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+int arr[6] = {1, 2, 3, 4, 5, 6};
+
+void f(void) {
+ for (int i = 0; i < 6; ++i) {
+ (void)arr[i];
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared-header.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared-header.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared-header.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared-header.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s modernize-make-shared %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-make-shared.MakeSmartPtrFunction, \
+// RUN: value: 'my::MakeShared'}, \
+// RUN: {key: modernize-make-shared.MakeSmartPtrFunctionHeader, \
+// RUN: value: 'make_shared_util.h'} \
+// RUN: ]}" \
+// RUN: -- -I %S/Inputs/modernize-smart-ptr
+
+#include "shared_ptr.h"
+// CHECK-FIXES: #include "make_shared_util.h"
+
+void f() {
+ std::shared_ptr<int> P1 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use my::MakeShared instead
+ // CHECK-FIXES: std::shared_ptr<int> P1 = my::MakeShared<int>();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-shared.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,297 @@
+// RUN: %check_clang_tidy %s modernize-make-shared %t -- -- -I %S/Inputs/modernize-smart-ptr
+
+#include "shared_ptr.h"
+// CHECK-FIXES: #include <memory>
+
+struct Base {
+ Base();
+ Base(int, int);
+};
+
+struct Derived : public Base {
+ Derived();
+ Derived(int, int);
+};
+
+struct APair {
+ int a, b;
+};
+
+struct DPair {
+ DPair() : a(0), b(0) {}
+ DPair(int x, int y) : a(y), b(x) {}
+ int a, b;
+};
+
+struct Empty {};
+
+template <class T>
+using shared_ptr_ = std::shared_ptr<T>;
+
+void *operator new(__SIZE_TYPE__ Count, void *Ptr);
+
+int g(std::shared_ptr<int> P);
+
+std::shared_ptr<Base> getPointer() {
+ return std::shared_ptr<Base>(new Base);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_shared instead
+ // CHECK-FIXES: return std::make_shared<Base>();
+}
+
+void basic() {
+ std::shared_ptr<int> P1 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: std::shared_ptr<int> P1 = std::make_shared<int>();
+
+ P1.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P1 = std::make_shared<int>();
+
+ P1 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P1 = std::make_shared<int>();
+
+ // Without parenthesis.
+ std::shared_ptr<int> P2 = std::shared_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: std::shared_ptr<int> P2 = std::make_shared<int>();
+
+ P2.reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P2 = std::make_shared<int>();
+
+ P2 = std::shared_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P2 = std::make_shared<int>();
+
+ // With auto.
+ auto P3 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead
+ // CHECK-FIXES: auto P3 = std::make_shared<int>();
+
+ std::shared_ptr<int> P4 = std::shared_ptr<int>((new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: std::shared_ptr<int> P4 = std::make_shared<int>();
+
+ P4.reset((((new int()))));
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P4 = std::make_shared<int>();
+
+ P4 = std::shared_ptr<int>(((new int)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P4 = std::make_shared<int>();
+
+ {
+ // No std.
+ using namespace std;
+ shared_ptr<int> Q = shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_shared instead
+ // CHECK-FIXES: shared_ptr<int> Q = std::make_shared<int>();
+
+ Q = shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: Q = std::make_shared<int>();
+ }
+
+ std::shared_ptr<int> R(new int());
+
+ // Create the shared_ptr as a parameter to a function.
+ int T = g(std::shared_ptr<int>(new int()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead
+ // CHECK-FIXES: int T = g(std::make_shared<int>());
+
+ // Only replace if the type in the template is the same as the type returned
+ // by the new operator.
+ auto Pderived = std::shared_ptr<Base>(new Derived());
+
+ // OK to replace for reset and assign
+ Pderived.reset(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::make_shared instead
+ // CHECK-FIXES: Pderived = std::make_shared<Derived>();
+
+ Pderived = std::shared_ptr<Derived>(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use std::make_shared instead
+ // CHECK-FIXES: Pderived = std::make_shared<Derived>();
+
+ // FIXME: OK to replace if assigned to shared_ptr<Base>
+ Pderived = std::shared_ptr<Base>(new Derived());
+
+ // FIXME: OK to replace when auto is not used
+ std::shared_ptr<Base> PBase = std::shared_ptr<Base>(new Derived());
+
+ // The pointer is returned by the function, nothing to do.
+ std::shared_ptr<Base> RetPtr = getPointer();
+
+ // This emulates std::move.
+ std::shared_ptr<int> Move = static_cast<std::shared_ptr<int> &&>(P1);
+
+ // Placement arguments should not be removed.
+ int *PInt = new int;
+ std::shared_ptr<int> Placement = std::shared_ptr<int>(new (PInt) int{3});
+ Placement.reset(new (PInt) int{3});
+ Placement = std::shared_ptr<int>(new (PInt) int{3});
+}
+
+// Calling make_smart_ptr from within a member function of a type with a
+// private or protected constructor would be ill-formed.
+class Private {
+private:
+ Private(int z) {}
+
+public:
+ Private() {}
+ void create() {
+ auto callsPublic = std::shared_ptr<Private>(new Private);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+ // CHECK-FIXES: auto callsPublic = std::make_shared<Private>();
+ auto ptr = std::shared_ptr<Private>(new Private(42));
+ ptr.reset(new Private(42));
+ ptr = std::shared_ptr<Private>(new Private(42));
+ }
+
+ virtual ~Private();
+};
+
+class Protected {
+protected:
+ Protected() {}
+
+public:
+ Protected(int, int) {}
+ void create() {
+ auto callsPublic = std::shared_ptr<Protected>(new Protected(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+ // CHECK-FIXES: auto callsPublic = std::make_shared<Protected>(1, 2);
+ auto ptr = std::shared_ptr<Protected>(new Protected);
+ ptr.reset(new Protected);
+ ptr = std::shared_ptr<Protected>(new Protected);
+ }
+};
+
+void initialization(int T, Base b) {
+ // Test different kinds of initialization of the pointee.
+
+ // Direct initialization with parenthesis.
+ std::shared_ptr<DPair> PDir1 = std::shared_ptr<DPair>(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir1 = std::make_shared<DPair>(1, T);
+ PDir1.reset(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: PDir1 = std::make_shared<DPair>(1, T);
+
+ // Direct initialization with braces.
+ std::shared_ptr<DPair> PDir2 = std::shared_ptr<DPair>(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir2 = std::make_shared<DPair>(2, T);
+ PDir2.reset(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: PDir2 = std::make_shared<DPair>(2, T);
+
+ // Aggregate initialization.
+ std::shared_ptr<APair> PAggr = std::shared_ptr<APair>(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<APair> PAggr = std::make_shared<APair>(APair{T, 1});
+ PAggr.reset(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: std::make_shared<APair>(APair{T, 1});
+
+ // Test different kinds of initialization of the pointee, when the shared_ptr
+ // is initialized with braces.
+
+ // Direct initialization with parenthesis.
+ std::shared_ptr<DPair> PDir3 = std::shared_ptr<DPair>{new DPair(3, T)};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir3 = std::make_shared<DPair>(3, T);
+
+ // Direct initialization with braces.
+ std::shared_ptr<DPair> PDir4 = std::shared_ptr<DPair>{new DPair{4, T}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir4 = std::make_shared<DPair>(4, T);
+
+ // Aggregate initialization.
+ std::shared_ptr<APair> PAggr2 = std::shared_ptr<APair>{new APair{T, 2}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<APair> PAggr2 = std::make_shared<APair>(APair{T, 2});
+
+ // Direct initialization with parenthesis, without arguments.
+ std::shared_ptr<DPair> PDir5 = std::shared_ptr<DPair>(new DPair());
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir5 = std::make_shared<DPair>();
+
+ // Direct initialization with braces, without arguments.
+ std::shared_ptr<DPair> PDir6 = std::shared_ptr<DPair>(new DPair{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir6 = std::make_shared<DPair>();
+
+ // Aggregate initialization without arguments.
+ std::shared_ptr<Empty> PEmpty = std::shared_ptr<Empty>(new Empty{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<Empty> PEmpty = std::make_shared<Empty>(Empty{});
+}
+
+void aliases() {
+ typedef std::shared_ptr<int> IntPtr;
+ IntPtr Typedef = IntPtr(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use std::make_shared instead
+ // CHECK-FIXES: IntPtr Typedef = std::make_shared<int>();
+
+ // We use 'bool' instead of '_Bool'.
+ typedef std::shared_ptr<bool> BoolPtr;
+ BoolPtr BoolType = BoolPtr(new bool);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::make_shared instead
+ // CHECK-FIXES: BoolPtr BoolType = std::make_shared<bool>();
+
+ // We use 'Base' instead of 'struct Base'.
+ typedef std::shared_ptr<Base> BasePtr;
+ BasePtr StructType = BasePtr(new Base);
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+// CHECK-FIXES: BasePtr StructType = std::make_shared<Base>();
+
+#define PTR shared_ptr<int>
+ std::shared_ptr<int> Macro = std::PTR(new int);
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead
+// CHECK-FIXES: std::shared_ptr<int> Macro = std::make_shared<int>();
+#undef PTR
+
+ std::shared_ptr<int> Using = shared_ptr_<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<int> Using = std::make_shared<int>();
+}
+
+void whitespaces() {
+ // clang-format off
+ auto Space = std::shared_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_shared instead
+ // CHECK-FIXES: auto Space = std::make_shared<int>();
+
+ auto Spaces = std :: shared_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_shared instead
+ // CHECK-FIXES: auto Spaces = std::make_shared<int>();
+ // clang-format on
+}
+
+void nesting() {
+ auto Nest = std::shared_ptr<std::shared_ptr<int>>(new std::shared_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use std::make_shared instead
+ // CHECK-FIXES: auto Nest = std::make_shared<std::shared_ptr<int>>(new int);
+ Nest.reset(new std::shared_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared instead
+ // CHECK-FIXES: Nest = std::make_shared<std::shared_ptr<int>>(new int);
+ Nest->reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: *Nest = std::make_shared<int>();
+}
+
+void reset() {
+ std::shared_ptr<int> P;
+ P.reset();
+ P.reset(nullptr);
+ P.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use std::make_shared instead
+ // CHECK-FIXES: P = std::make_shared<int>();
+
+ auto Q = &P;
+ Q->reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared instead
+ // CHECK-FIXES: *Q = std::make_shared<int>();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-cxx11.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-cxx11.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-cxx11.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy -std=c++11 %s modernize-make-unique %t -- -- -I %S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include "unique_ptr.h"
+
+void f() {
+ auto my_ptr = std::unique_ptr<int>(new int(1));
+ // CHECK-FIXES: auto my_ptr = std::unique_ptr<int>(new int(1));
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-header.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-header.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-header.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-header.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-make-unique.MakeSmartPtrFunction, \
+// RUN: value: 'my::MakeUnique'}, \
+// RUN: {key: modernize-make-unique.MakeSmartPtrFunctionHeader, \
+// RUN: value: 'make_unique_util.h'} \
+// RUN: ]}" \
+// RUN: -- -I %S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include "make_unique_util.h"
+
+void f() {
+ std::unique_ptr<int> P1 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use my::MakeUnique instead
+ // CHECK-FIXES: std::unique_ptr<int> P1 = my::MakeUnique<int>();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-inaccessible-ctors.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-inaccessible-ctors.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-inaccessible-ctors.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-inaccessible-ctors.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,113 @@
+// RUN: %check_clang_tidy -std=c++14,c++17 -check-suffix=CXX-14-17 %s modernize-make-unique %t -- -- -I %S/Inputs/modernize-smart-ptr -D CXX_14_17=1
+// RUN: %check_clang_tidy -std=c++2a -check-suffix=CXX-2A %s modernize-make-unique %t -- -- -I %S/Inputs/modernize-smart-ptr -D CXX_2A=1
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include <memory>
+
+struct NoCopyMoveCtor {
+#ifdef CXX_2A
+ // C++2a requires to see the default constructor, otherwise it is illgal.
+ NoCopyMoveCtor() = default;
+#endif
+#ifdef CXX_14_17
+ int a, b;
+#endif
+ NoCopyMoveCtor(const NoCopyMoveCtor &) = delete; // implies move ctor is deleted
+};
+
+struct NoCopyMoveCtorVisible {
+#ifdef CXX_2A
+ NoCopyMoveCtorVisible() = default;
+#endif
+private:
+ NoCopyMoveCtorVisible(const NoCopyMoveCtorVisible&) = default;
+ NoCopyMoveCtorVisible(NoCopyMoveCtorVisible&&) = default;
+};
+
+struct OnlyMoveCtor {
+ OnlyMoveCtor() = default;
+ OnlyMoveCtor(OnlyMoveCtor&&) = default;
+ OnlyMoveCtor(const OnlyMoveCtor &) = delete;
+};
+
+struct OnlyCopyCtor {
+#ifdef CXX_2A
+ OnlyCopyCtor() = default;
+#endif
+ OnlyCopyCtor(const OnlyCopyCtor&) = default;
+ OnlyCopyCtor(OnlyCopyCtor&&) = delete;
+};
+
+struct OnlyCopyCtorVisible {
+#ifdef CXX_2A
+ OnlyCopyCtorVisible() = default;
+#endif
+ OnlyCopyCtorVisible(const OnlyCopyCtorVisible &) = default;
+
+private:
+ OnlyCopyCtorVisible(OnlyCopyCtorVisible &&) = default;
+};
+
+struct ImplicitDeletedCopyCtor {
+ const OnlyMoveCtor ctor;
+};
+
+void f() {
+ auto my_ptr = std::unique_ptr<int>(new int(1));
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:17: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto my_ptr = std::make_unique<int>(1);
+ // CHECK-MESSAGES-CXX-2A: :[[@LINE-3]]:17: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-2A: auto my_ptr = std::make_unique<int>(1);
+
+ // "new NoCopyMoveCtor{}" is processed differently in C++14/17 and C++2a:
+ // * In C++14/17, it is recognized as aggregate initialization,
+ // no fixes will be generated although the generated fix is compilable.
+ // * In C++2a, it is is recognized as default constructor initialization (
+ // similar to "new NoCopyMoveCtor()"), the check will emit the fix and the
+ // fix is correct.
+ auto PNoCopyMoveCtor = std::unique_ptr<NoCopyMoveCtor>(new NoCopyMoveCtor{});
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:26: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto PNoCopyMoveCtor = std::unique_ptr<NoCopyMoveCtor>(new NoCopyMoveCtor{});
+ // CHECK-MESSAGES-CXX-2A: :[[@LINE-3]]:26: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-2A: auto PNoCopyMoveCtor = std::make_unique<NoCopyMoveCtor>();
+
+ auto PNoCopyMoveCtorVisible = std::unique_ptr<NoCopyMoveCtorVisible>(new NoCopyMoveCtorVisible{});
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:33: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto PNoCopyMoveCtorVisible = std::unique_ptr<NoCopyMoveCtorVisible>(new NoCopyMoveCtorVisible{});
+ // CHECK-MESSAGES-CXX-2A: :[[@LINE-3]]:33: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-2A: auto PNoCopyMoveCtorVisible = std::make_unique<NoCopyMoveCtorVisible>();
+
+ auto POnlyMoveCtor = std::unique_ptr<OnlyMoveCtor>(new OnlyMoveCtor{});
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto POnlyMoveCtor = std::unique_ptr<OnlyMoveCtor>(new OnlyMoveCtor{});
+ // CHECK-MESSAGES-CXX-2A: :[[@LINE-3]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-2A: auto POnlyMoveCtor = std::make_unique<OnlyMoveCtor>();
+
+ auto POnlyCopyCtor = std::unique_ptr<OnlyCopyCtor>(new OnlyCopyCtor{});
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto POnlyCopyCtor = std::unique_ptr<OnlyCopyCtor>(new OnlyCopyCtor{});
+ // CHECK-MESSAGES-CXX-2A: :[[@LINE-3]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-2A: auto POnlyCopyCtor = std::make_unique<OnlyCopyCtor>();
+
+ auto POnlyCopyCtorVisible = std::unique_ptr<OnlyCopyCtorVisible>(new OnlyCopyCtorVisible{});
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:31: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto POnlyCopyCtorVisible = std::unique_ptr<OnlyCopyCtorVisible>(new OnlyCopyCtorVisible{});
+ // CHECK-MESSAGES-CXX-2A: :[[@LINE-3]]:31: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-2A: auto POnlyCopyCtorVisible = std::make_unique<OnlyCopyCtorVisible>();
+
+ // This is aggregate initialization in C++2a, no fix will be generated.
+ auto PImplicitDeletedCopyCtor = std::unique_ptr<ImplicitDeletedCopyCtor>(new ImplicitDeletedCopyCtor{});
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:35: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto PImplicitDeletedCopyCtor = std::unique_ptr<ImplicitDeletedCopyCtor>(new ImplicitDeletedCopyCtor{});
+ // CHECK-MESSAGES-CXX-2A: :[[@LINE-3]]:35: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-2A: auto PImplicitDeletedCopyCtor = std::unique_ptr<ImplicitDeletedCopyCtor>(new ImplicitDeletedCopyCtor{});
+
+
+#ifdef CXX_14_17
+ // FIXME: it is impossible to use make_unique for this case, the check should
+ // stop emitting the message.
+ auto PNoCopyMoveCtor2 = std::unique_ptr<NoCopyMoveCtor>(new NoCopyMoveCtor{1, 2});
+ // CHECK-MESSAGES-CXX-14-17: :[[@LINE-1]]:27: warning: use std::make_unique instead
+ // CHECK-FIXES-CXX-14-17: auto PNoCopyMoveCtor2 = std::unique_ptr<NoCopyMoveCtor>(new NoCopyMoveCtor{1, 2});
+#endif
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-macros.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-macros.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-macros.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique-macros.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-make-unique %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-make-unique.IgnoreMacros, value: 0}]}" \
+// RUN: -- -I %S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+
+class Foo {};
+class Bar {};
+#define DEFINE(...) __VA_ARGS__
+// CHECK-FIXES: {{^}}#define DEFINE(...) __VA_ARGS__{{$}}
+template<typename T>
+void g2(std::unique_ptr<Foo> *t) {
+ DEFINE(
+ // CHECK-FIXES: {{^ *}}DEFINE({{$}}
+ auto p = std::unique_ptr<Foo>(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_unique instead
+ // CHECK-FIXES: {{^ *}}auto p = std::unique_ptr<Foo>(new Foo);{{$}}
+ t->reset(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_unique instead
+ // CHECK-FIXES: {{^ *}}t->reset(new Foo);{{$}}
+ );
+ // CHECK-FIXES: {{^ *}});{{$}}
+}
+void macro() {
+ std::unique_ptr<Foo> *t;
+ g2<Bar>(t);
+}
+#undef DEFINE
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-make-unique.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,570 @@
+// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-make-unique %t -- -- -I %S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+#include "initializer_list.h"
+// CHECK-FIXES: #include <memory>
+
+struct Base {
+ Base();
+ Base(int, int);
+};
+
+struct Derived : public Base {
+ Derived();
+ Derived(int, int);
+};
+
+struct APair {
+ int a, b;
+};
+
+struct DPair {
+ DPair() : a(0), b(0) {}
+ DPair(int x, int y) : a(y), b(x) {}
+ int a, b;
+};
+
+template<typename T>
+struct MyVector {
+ MyVector(std::initializer_list<T>);
+};
+
+struct Empty {};
+
+
+struct E {
+ E(std::initializer_list<int>);
+ E();
+};
+
+struct F {
+ F(std::initializer_list<int>);
+ F();
+ int a;
+};
+
+struct G {
+ G(std::initializer_list<int>);
+ G(int);
+};
+
+struct H {
+ H(std::vector<int>);
+ H(std::vector<int> &, double);
+ H(MyVector<int>, int);
+};
+
+struct I {
+ I(G);
+};
+
+struct J {
+ J(E e, int);
+};
+
+namespace {
+class Foo {};
+} // namespace
+
+namespace bar {
+class Bar {};
+} // namespace bar
+
+template <class T>
+using unique_ptr_ = std::unique_ptr<T>;
+
+void *operator new(__SIZE_TYPE__ Count, void *Ptr);
+
+int g(std::unique_ptr<int> P);
+
+std::unique_ptr<Base> getPointer() {
+ return std::unique_ptr<Base>(new Base);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_unique instead
+ // CHECK-FIXES: return std::make_unique<Base>();
+}
+
+void basic() {
+ std::unique_ptr<int> P1 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: std::unique_ptr<int> P1 = std::make_unique<int>();
+
+ P1.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P1 = std::make_unique<int>();
+
+ P1 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P1 = std::make_unique<int>();
+
+ // Without parenthesis.
+ std::unique_ptr<int> P2 = std::unique_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: std::unique_ptr<int> P2 = std::make_unique<int>();
+
+ P2.reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P2 = std::make_unique<int>();
+
+ P2 = std::unique_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P2 = std::make_unique<int>();
+
+ // With auto.
+ auto P3 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique instead
+ // CHECK-FIXES: auto P3 = std::make_unique<int>();
+
+ std::unique_ptr<int> P4 = std::unique_ptr<int>((new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: std::unique_ptr<int> P4 = std::make_unique<int>();
+ P4.reset((new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P4 = std::make_unique<int>();
+ std::unique_ptr<int> P5 = std::unique_ptr<int>((((new int))));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: std::unique_ptr<int> P5 = std::make_unique<int>();
+ P5.reset(((((new int)))));
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P5 = std::make_unique<int>();
+
+ {
+ // No std.
+ using namespace std;
+ unique_ptr<int> Q = unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_unique instead
+ // CHECK-FIXES: unique_ptr<int> Q = std::make_unique<int>();
+
+ Q = unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: Q = std::make_unique<int>();
+ }
+
+ std::unique_ptr<int> R(new int());
+
+ // Create the unique_ptr as a parameter to a function.
+ int T = g(std::unique_ptr<int>(new int()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique instead
+ // CHECK-FIXES: int T = g(std::make_unique<int>());
+
+ // Only replace if the type in the template is the same as the type returned
+ // by the new operator.
+ auto Pderived = std::unique_ptr<Base>(new Derived());
+
+ // OK to replace for reset and assign
+ Pderived.reset(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::make_unique instead
+ // CHECK-FIXES: Pderived = std::make_unique<Derived>();
+
+ Pderived = std::unique_ptr<Derived>(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use std::make_unique instead
+ // CHECK-FIXES: Pderived = std::make_unique<Derived>();
+
+ // FIXME: OK to replace if assigned to unique_ptr<Base>
+ Pderived = std::unique_ptr<Base>(new Derived());
+
+ // FIXME: OK to replace when auto is not used
+ std::unique_ptr<Base> PBase = std::unique_ptr<Base>(new Derived());
+
+ // The pointer is returned by the function, nothing to do.
+ std::unique_ptr<Base> RetPtr = getPointer();
+
+ // This emulates std::move.
+ std::unique_ptr<int> Move = static_cast<std::unique_ptr<int> &&>(P1);
+
+ // Placement arguments should not be removed.
+ int *PInt = new int;
+ std::unique_ptr<int> Placement = std::unique_ptr<int>(new (PInt) int{3});
+ Placement.reset(new (PInt) int{3});
+ Placement = std::unique_ptr<int>(new (PInt) int{3});
+}
+
+// Calling make_smart_ptr from within a member function of a type with a
+// private or protected constructor would be ill-formed.
+class Private {
+private:
+ Private(int z) {}
+
+public:
+ Private() {}
+ void create() {
+ auto callsPublic = std::unique_ptr<Private>(new Private);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES: auto callsPublic = std::make_unique<Private>();
+ auto ptr = std::unique_ptr<Private>(new Private(42));
+ ptr.reset(new Private(42));
+ ptr = std::unique_ptr<Private>(new Private(42));
+ }
+
+ virtual ~Private();
+};
+
+class Protected {
+protected:
+ Protected() {}
+
+public:
+ Protected(int, int) {}
+ void create() {
+ auto callsPublic = std::unique_ptr<Protected>(new Protected(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES: auto callsPublic = std::make_unique<Protected>(1, 2);
+ auto ptr = std::unique_ptr<Protected>(new Protected);
+ ptr.reset(new Protected);
+ ptr = std::unique_ptr<Protected>(new Protected);
+ }
+};
+
+void initialization(int T, Base b) {
+ // Test different kinds of initialization of the pointee.
+
+ // Direct initialization with parenthesis.
+ std::unique_ptr<DPair> PDir1 = std::unique_ptr<DPair>(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir1 = std::make_unique<DPair>(1, T);
+ PDir1.reset(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: PDir1 = std::make_unique<DPair>(1, T);
+
+ // Direct initialization with braces.
+ std::unique_ptr<DPair> PDir2 = std::unique_ptr<DPair>(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir2 = std::make_unique<DPair>(2, T);
+ PDir2.reset(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: PDir2 = std::make_unique<DPair>(2, T);
+
+ // Aggregate initialization.
+ std::unique_ptr<APair> PAggr = std::unique_ptr<APair>(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<APair> PAggr = std::make_unique<APair>(APair{T, 1});
+ PAggr.reset(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: std::make_unique<APair>(APair{T, 1});
+
+ // Check aggregate init with intermediate temporaries.
+ std::unique_ptr<APair> PAggrTemp = std::unique_ptr<APair>(new APair({T, 1}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<APair> PAggrTemp = std::unique_ptr<APair>(new APair({T, 1}));
+ PAggrTemp.reset(new APair({T, 1}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique instead
+ // CHECK-FIXES: PAggrTemp.reset(new APair({T, 1}));
+
+ // Test different kinds of initialization of the pointee, when the unique_ptr
+ // is initialized with braces.
+
+ // Direct initialization with parenthesis.
+ std::unique_ptr<DPair> PDir3 = std::unique_ptr<DPair>{new DPair(3, T)};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir3 = std::make_unique<DPair>(3, T);
+
+ // Direct initialization with braces.
+ std::unique_ptr<DPair> PDir4 = std::unique_ptr<DPair>{new DPair{4, T}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir4 = std::make_unique<DPair>(4, T);
+
+ // Aggregate initialization.
+ std::unique_ptr<APair> PAggr2 = std::unique_ptr<APair>{new APair{T, 2}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<APair> PAggr2 = std::make_unique<APair>(APair{T, 2});
+
+ // Direct initialization with parenthesis, without arguments.
+ std::unique_ptr<DPair> PDir5 = std::unique_ptr<DPair>(new DPair());
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir5 = std::make_unique<DPair>();
+
+ // Direct initialization with braces, without arguments.
+ std::unique_ptr<DPair> PDir6 = std::unique_ptr<DPair>(new DPair{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir6 = std::make_unique<DPair>();
+
+ // Aggregate initialization without arguments.
+ std::unique_ptr<Empty> PEmpty = std::unique_ptr<Empty>(new Empty{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<Empty> PEmpty = std::make_unique<Empty>(Empty{});
+
+ // Initialization with default constructor.
+ std::unique_ptr<E> PE1 = std::unique_ptr<E>(new E{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<E> PE1 = std::make_unique<E>();
+ PE1.reset(new E{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PE1 = std::make_unique<E>();
+
+ // No warnings for `auto` new expression.
+ PE1.reset(new auto(E()));
+
+ //============================================================================
+ // NOTE: For initlializer-list constructors, the check only gives warnings,
+ // and no fixes are generated.
+ //============================================================================
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<E> PE2 = std::unique_ptr<E>(new E{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<E> PE2 = std::unique_ptr<E>(new E{1, 2});
+ PE2.reset(new E{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PE2.reset(new E{1, 2});
+
+ // Initialization with default constructor.
+ std::unique_ptr<F> PF1 = std::unique_ptr<F>(new F());
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF1 = std::make_unique<F>();
+ PF1.reset(new F());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PF1 = std::make_unique<F>();
+
+ // Initialization with default constructor.
+ std::unique_ptr<F> PF2 = std::unique_ptr<F>(new F{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF2 = std::make_unique<F>();
+ PF2.reset(new F());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PF2 = std::make_unique<F>();
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<F> PF3 = std::unique_ptr<F>(new F{1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF3 = std::unique_ptr<F>(new F{1});
+ PF3.reset(new F{1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PF3.reset(new F{1});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<F> PF4 = std::unique_ptr<F>(new F{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF4 = std::unique_ptr<F>(new F{1, 2});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<F> PF5 = std::unique_ptr<F>(new F({1, 2}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF5 = std::unique_ptr<F>(new F({1, 2}));
+
+ // Initialization with the initializer-list constructor as the default
+ // constructor is not present.
+ std::unique_ptr<G> PG1 = std::unique_ptr<G>(new G{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<G> PG1 = std::unique_ptr<G>(new G{});
+ PG1.reset(new G{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PG1.reset(new G{});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<G> PG2 = std::unique_ptr<G>(new G{1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<G> PG2 = std::unique_ptr<G>(new G{1});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<G> PG3 = std::unique_ptr<G>(new G{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<G> PG3 = std::unique_ptr<G>(new G{1, 2});
+
+ std::unique_ptr<H> PH1 = std::unique_ptr<H>(new H({1, 2, 3}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<H> PH1 = std::unique_ptr<H>(new H({1, 2, 3}));
+ PH1.reset(new H({1, 2, 3}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PH1.reset(new H({1, 2, 3}));
+
+ std::unique_ptr<H> PH2 = std::unique_ptr<H>(new H({1, 2, 3}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<H> PH2 = std::unique_ptr<H>(new H({1, 2, 3}, 1));
+ PH2.reset(new H({1, 2, 3}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PH2.reset(new H({1, 2, 3}, 1));
+
+ std::unique_ptr<H> PH3 = std::unique_ptr<H>(new H({1, 2, 3}, 1.0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<H> PH3 = std::unique_ptr<H>(new H({1, 2, 3}, 1.0));
+ PH3.reset(new H({1, 2, 3}, 1.0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PH3.reset(new H({1, 2, 3}, 1.0));
+
+ std::unique_ptr<I> PI1 = std::unique_ptr<I>(new I(G({1, 2, 3})));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<I> PI1 = std::make_unique<I>(G({1, 2, 3}));
+ PI1.reset(new I(G({1, 2, 3})));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PI1 = std::make_unique<I>(G({1, 2, 3}));
+
+ std::unique_ptr<J> PJ1 = std::unique_ptr<J>(new J({1, 2}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<J> PJ1 = std::unique_ptr<J>(new J({1, 2}, 1));
+ PJ1.reset(new J({1, 2}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PJ1.reset(new J({1, 2}, 1));
+
+ std::unique_ptr<J> PJ2 = std::unique_ptr<J>(new J(E{1, 2}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<J> PJ2 = std::unique_ptr<J>(new J(E{1, 2}, 1));
+ PJ2.reset(new J(E{1, 2}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PJ2.reset(new J(E{1, 2}, 1));
+
+ std::unique_ptr<J> PJ3 = std::unique_ptr<J>(new J{ {1, 2}, 1 });
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<J> PJ3 = std::unique_ptr<J>(new J{ {1, 2}, 1 });
+ PJ3.reset(new J{ {1, 2}, 1 });
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PJ3.reset(new J{ {1, 2}, 1 });
+
+ std::unique_ptr<J> PJ4 = std::unique_ptr<J>(new J{E{1, 2}, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<J> PJ4 = std::unique_ptr<J>(new J{E{1, 2}, 1});
+ PJ4.reset(new J{E{1, 2}, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PJ4.reset(new J{E{1, 2}, 1});
+
+ std::unique_ptr<Foo> FF = std::unique_ptr<Foo>(new Foo());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning:
+ // CHECK-FIXES: std::unique_ptr<Foo> FF = std::make_unique<Foo>();
+ FF.reset(new Foo());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: FF = std::make_unique<Foo>();
+
+ std::unique_ptr<bar::Bar> BB = std::unique_ptr<bar::Bar>(new bar::Bar());
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning:
+ // CHECK-FIXES: std::unique_ptr<bar::Bar> BB = std::make_unique<bar::Bar>();
+ BB.reset(new bar::Bar());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: BB = std::make_unique<bar::Bar>();
+
+ std::unique_ptr<Foo[]> FFs;
+ FFs.reset(new Foo[5]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(5);
+ FFs.reset(new Foo[5]());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(5);
+ const int Num = 1;
+ FFs.reset(new Foo[Num]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(Num);
+ int Num2 = 1;
+ FFs.reset(new Foo[Num2]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(Num2);
+
+ std::unique_ptr<int[]> FI;
+ FI.reset(new int[5]()); // default initialization.
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: FI = std::make_unique<int[]>(5);
+
+ // The check doesn't give warnings and fixes for cases where the original new
+ // expresion doesn't do any initialization.
+ FI.reset(new int[5]);
+ FI.reset(new int[Num]);
+ FI.reset(new int[Num2]);
+}
+
+void aliases() {
+ typedef std::unique_ptr<int> IntPtr;
+ IntPtr Typedef = IntPtr(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use std::make_unique instead
+ // CHECK-FIXES: IntPtr Typedef = std::make_unique<int>();
+
+ // We use 'bool' instead of '_Bool'.
+ typedef std::unique_ptr<bool> BoolPtr;
+ BoolPtr BoolType = BoolPtr(new bool);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::make_unique instead
+ // CHECK-FIXES: BoolPtr BoolType = std::make_unique<bool>();
+
+ // We use 'Base' instead of 'struct Base'.
+ typedef std::unique_ptr<Base> BasePtr;
+ BasePtr StructType = BasePtr(new Base);
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+// CHECK-FIXES: BasePtr StructType = std::make_unique<Base>();
+
+#define PTR unique_ptr<int>
+ std::unique_ptr<int> Macro = std::PTR(new int);
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_unique instead
+// CHECK-FIXES: std::unique_ptr<int> Macro = std::make_unique<int>();
+#undef PTR
+
+ std::unique_ptr<int> Using = unique_ptr_<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<int> Using = std::make_unique<int>();
+}
+
+void whitespaces() {
+ // clang-format off
+ auto Space = std::unique_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_unique instead
+ // CHECK-FIXES: auto Space = std::make_unique<int>();
+
+ auto Spaces = std :: unique_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_unique instead
+ // CHECK-FIXES: auto Spaces = std::make_unique<int>();
+ // clang-format on
+}
+
+void nesting() {
+ auto Nest = std::unique_ptr<std::unique_ptr<int>>(new std::unique_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use std::make_unique instead
+ // CHECK-FIXES: auto Nest = std::make_unique<std::unique_ptr<int>>(new int);
+ Nest.reset(new std::unique_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_unique instead
+ // CHECK-FIXES: Nest = std::make_unique<std::unique_ptr<int>>(new int);
+ Nest->reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: *Nest = std::make_unique<int>();
+}
+
+void reset() {
+ std::unique_ptr<int> P;
+ P.reset();
+ P.reset(nullptr);
+ P.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use std::make_unique instead
+ // CHECK-FIXES: P = std::make_unique<int>();
+
+ auto Q = &P;
+ Q->reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead
+ // CHECK-FIXES: *Q = std::make_unique<int>();
+}
+
+#define DEFINE(...) __VA_ARGS__
+template<typename T>
+void g2(std::unique_ptr<Foo> *t) {
+ DEFINE(auto p = std::unique_ptr<Foo>(new Foo); t->reset(new Foo););
+}
+void macro() {
+ std::unique_ptr<Foo> *t;
+ g2<bar::Bar>(t);
+}
+#undef DEFINE
+
+class UniqueFoo : public std::unique_ptr<Foo> {
+ public:
+ void foo() {
+ reset(new Foo);
+ this->reset(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use std::make_unique instead
+ // CHECK-FIXES: *this = std::make_unique<Foo>();
+ (*this).reset(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique instead
+ // CHECK-FIXES: (*this) = std::make_unique<Foo>();
+ }
+};
+
+// Ignore statements inside a template instantiation.
+template<typename T>
+void template_fun(T* t) {
+ std::unique_ptr<T> t2 = std::unique_ptr<T>(new T);
+ t2.reset(new T);
+}
+
+void invoke_template() {
+ Foo* foo;
+ template_fun(foo);
+}
+
+void no_fix_for_invalid_new_loc() {
+ // FIXME: Although the code is valid, the end location of `new struct Base` is
+ // invalid. Correct it once https://bugs.llvm.org/show_bug.cgi?id=35952 is
+ // fixed.
+ auto T = std::unique_ptr<Base>(new struct Base);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::make_unique instead
+ // CHECK-FIXES: auto T = std::unique_ptr<Base>(new struct Base);
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-header.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-header.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-header.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-header.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,9 @@
+// RUN: cp %S/Inputs/modernize-pass-by-value/header.h %T/pass-by-value-header.h
+// RUN: clang-tidy %s -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %T | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:"
+// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=CHECK-FIXES
+// FIXME: Make the test work in all language modes.
+
+#include "pass-by-value-header.h"
+// CHECK-MESSAGES: :8:5: warning: pass by value and use std::move [modernize-pass-by-value]
+// CHECK-FIXES: #include <utility>
+// CHECK-FIXES: A(ThreadId tid) : threadid(std::move(tid)) {}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-macro-header.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-macro-header.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-macro-header.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-macro-header.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -isystem %S/Inputs/Headers
+
+// CHECK-FIXES: #include <utility>
+
+#define HEADER <./a.h>
+#include HEADER
+
+struct A {
+ A(const A &) {}
+ A(A &&) {}
+};
+
+struct B {
+ B(const A &a) : a(a) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value]
+// CHECK-FIXES: B(A a) : a(std::move(a)) {}
+ A a;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-multi-fixes.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-multi-fixes.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-multi-fixes.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value-multi-fixes.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,12 @@
+// RUN: cat %S/Inputs/modernize-pass-by-value/header-with-fix.h > %T/pass-by-value-header-with-fix.h
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %T | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:"
+// RUN: FileCheck -input-file=%t.cpp %s -check-prefix=CHECK-FIXES
+// RUN: FileCheck -input-file=%T/pass-by-value-header-with-fix.h %s -check-prefix=CHECK-HEADER-FIXES
+
+#include "pass-by-value-header-with-fix.h"
+// CHECK-HEADER-FIXES: Foo(S s);
+Foo::Foo(const S &s) : s(s) {}
+// CHECK-MESSAGES: :9:10: warning: pass by value and use std::move [modernize-pass-by-value]
+// CHECK-FIXES: #include <utility>
+// CHECK-FIXES: Foo::Foo(S s) : s(std::move(s)) {}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-pass-by-value.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,215 @@
+// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -fno-delayed-template-parsing
+
+namespace {
+// POD types are trivially move constructible.
+struct POD {
+ int a, b, c;
+};
+
+struct Movable {
+ int a, b, c;
+ Movable() = default;
+ Movable(const Movable &) {}
+ Movable(Movable &&) {}
+};
+
+struct NotMovable {
+ NotMovable() = default;
+ NotMovable(const NotMovable &) = default;
+ NotMovable(NotMovable &&) = delete;
+ int a, b, c;
+};
+}
+
+struct A {
+ A(const Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value]
+ // CHECK-FIXES: A(Movable M) : M(std::move(M)) {}
+ Movable M;
+};
+
+// Test that we aren't modifying other things than a parameter.
+Movable GlobalObj;
+struct B {
+ B(const Movable &M) : M(GlobalObj) {}
+ // CHECK-FIXES: B(const Movable &M) : M(GlobalObj) {}
+ Movable M;
+};
+
+// Test that a parameter with more than one reference to it won't be changed.
+struct C {
+ // Tests extra-reference in body.
+ C(const Movable &M) : M(M) { this->i = M.a; }
+ // CHECK-FIXES: C(const Movable &M) : M(M) { this->i = M.a; }
+
+ // Tests extra-reference in init-list.
+ C(const Movable &M, int) : M(M), i(M.a) {}
+ // CHECK-FIXES: C(const Movable &M, int) : M(M), i(M.a) {}
+ Movable M;
+ int i;
+};
+
+// Test that both declaration and definition are updated.
+struct D {
+ D(const Movable &M);
+ // CHECK-FIXES: D(Movable M);
+ Movable M;
+};
+D::D(const Movable &M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: D::D(Movable M) : M(std::move(M)) {}
+
+// Test with default parameter.
+struct E {
+ E(const Movable &M = Movable()) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: E(Movable M = Movable()) : M(std::move(M)) {}
+ Movable M;
+};
+
+// Test with object that can't be moved.
+struct F {
+ F(const NotMovable &NM) : NM(NM) {}
+ // CHECK-FIXES: F(const NotMovable &NM) : NM(NM) {}
+ NotMovable NM;
+};
+
+// Test unnamed parameter in declaration.
+struct G {
+ G(const Movable &);
+ // CHECK-FIXES: G(Movable );
+ Movable M;
+};
+G::G(const Movable &M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: G::G(Movable M) : M(std::move(M)) {}
+
+// Test parameter with and without qualifier.
+namespace ns_H {
+typedef ::Movable HMovable;
+}
+struct H {
+ H(const ns_H::HMovable &M);
+ // CHECK-FIXES: H(ns_H::HMovable M);
+ ns_H::HMovable M;
+};
+using namespace ns_H;
+H::H(const HMovable &M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: H(HMovable M) : M(std::move(M)) {}
+
+// Try messing up with macros.
+#define MOVABLE_PARAM(Name) const Movable & Name
+// CHECK-FIXES: #define MOVABLE_PARAM(Name) const Movable & Name
+struct I {
+ I(MOVABLE_PARAM(M)) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: I(MOVABLE_PARAM(M)) : M(M) {}
+ Movable M;
+};
+#undef MOVABLE_PARAM
+
+// Test that templates aren't modified.
+template <typename T> struct J {
+ J(const T &M) : M(M) {}
+ // CHECK-FIXES: J(const T &M) : M(M) {}
+ T M;
+};
+J<Movable> j1(Movable());
+J<NotMovable> j2(NotMovable());
+
+struct K_Movable {
+ K_Movable() = default;
+ K_Movable(const K_Movable &) = default;
+ K_Movable(K_Movable &&o) { dummy = o.dummy; }
+ int dummy;
+};
+
+// Test with movable type with an user defined move constructor.
+struct K {
+ K(const K_Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: K(K_Movable M) : M(std::move(M)) {}
+ K_Movable M;
+};
+
+template <typename T> struct L {
+ L(const Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: L(Movable M) : M(std::move(M)) {}
+ Movable M;
+};
+L<int> l(Movable());
+
+// Test with a non-instantiated template class.
+template <typename T> struct N {
+ N(const Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: N(Movable M) : M(std::move(M)) {}
+
+ Movable M;
+ T A;
+};
+
+// Test with value parameter.
+struct O {
+ O(Movable M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: O(Movable M) : M(std::move(M)) {}
+ Movable M;
+};
+
+// Test with a const-value parameter.
+struct P {
+ P(const Movable M) : M(M) {}
+ // CHECK-FIXES: P(const Movable M) : M(M) {}
+ Movable M;
+};
+
+// Test with multiples parameters where some need to be changed and some don't.
+// need to.
+struct Q {
+ Q(const Movable &A, const Movable &B, const Movable &C, double D)
+ : A(A), B(B), C(C), D(D) {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: pass by value and use std::move
+ // CHECK-MESSAGES: :[[@LINE-3]]:41: warning: pass by value and use std::move
+ // CHECK-FIXES: Q(const Movable &A, Movable B, Movable C, double D)
+ // CHECK-FIXES: : A(A), B(std::move(B)), C(std::move(C)), D(D) {}
+ const Movable &A;
+ Movable B;
+ Movable C;
+ double D;
+};
+
+// Test that value-parameters with a nested name specifier are left as-is.
+namespace ns_R {
+typedef ::Movable RMovable;
+}
+struct R {
+ R(ns_R::RMovable M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: R(ns_R::RMovable M) : M(std::move(M)) {}
+ ns_R::RMovable M;
+};
+
+// Test with rvalue parameter.
+struct S {
+ S(Movable &&M) : M(M) {}
+ // CHECK-FIXES: S(Movable &&M) : M(M) {}
+ Movable M;
+};
+
+template <typename T, int N> struct array { T A[N]; };
+
+// Test that types that are trivially copyable will not use std::move. This will
+// cause problems with performance-move-const-arg, as it will revert it.
+struct T {
+ T(array<int, 10> a) : a_(a) {}
+ // CHECK-FIXES: T(array<int, 10> a) : a_(a) {}
+ array<int, 10> a_;
+};
+
+struct U {
+ U(const POD &M) : M(M) {}
+ POD M;
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-delimiter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-delimiter.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-delimiter.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-delimiter.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s modernize-raw-string-literal %t -- -config='{CheckOptions: [{key: "modernize-raw-string-literal.DelimiterStem", value: "str"}, {key: modernize-raw-string-literal.ReplaceShorterLiterals, value: 1}]}'
+
+char const *const ContainsSentinel{"who\\ops)\""};
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ContainsSentinel{R"str(who\ops)")str"};{{$}}
+
+//char const *const ContainsDelim{"whoops)\")lit\""};
+// CHECK-XMESSAGES: :[[@LINE-1]]:33: warning: {{.*}} can be written as a raw string literal
+// CHECK-XFIXES: {{^}}char const *const ContainsDelim{R"lit1(whoops)")lit")lit1"};{{$}}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-replace-shorter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-replace-shorter.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-replace-shorter.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal-replace-shorter.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s modernize-raw-string-literal %t
+
+// Don't replace these, because the raw literal would be longer.
+char const *const JustAQuote("quote:\'");
+char const *const NeedDelimiter("\":)\"");
+
+char const *const ManyQuotes("quotes:\'\'\'\'");
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ManyQuotes(R"(quotes:'''')");{{$}}
+
+char const *const LongOctal("\042\072\051\042");
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const LongOctal(R"lit(":)")lit");{{$}}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-raw-string-literal.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,132 @@
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s modernize-raw-string-literal %t -- -config="{CheckOptions: [{key: modernize-raw-string-literal.ReplaceShorterLiterals, value: 1}]}"
+// FIXME: Fix the checker to work in C++2a mode.
+
+char const *const BackSlash("goink\\frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: escaped string literal can be written as a raw string literal [modernize-raw-string-literal]
+// CHECK-FIXES: {{^}}char const *const BackSlash(R"(goink\frob)");{{$}}
+
+char const *const PlainLiteral("plain literal");
+
+// Non-printable ASCII characters.
+char const *const Nul("goink\\\000");
+char const *const Soh("goink\\\001");
+char const *const Stx("goink\\\002");
+char const *const Etx("goink\\\003");
+char const *const Enq("goink\\\004");
+char const *const Ack("goink\\\005");
+char const *const Bell("goink\\\afrob");
+char const *const BackSpace("goink\\\bfrob");
+char const *const HorizontalTab("goink\\\tfrob");
+char const *const NewLine("goink\nfrob");
+char const *const VerticalTab("goink\\\vfrob");
+char const *const FormFeed("goink\\\ffrob");
+char const *const CarraigeReturn("goink\\\rfrob");
+char const *const So("goink\\\016");
+char const *const Si("goink\\\017");
+char const *const Dle("goink\\\020");
+char const *const Dc1("goink\\\021");
+char const *const Dc2("goink\\\022");
+char const *const Dc3("goink\\\023");
+char const *const Dc4("goink\\\024");
+char const *const Nak("goink\\\025");
+char const *const Syn("goink\\\026");
+char const *const Etb("goink\\\027");
+char const *const Can("goink\\\030");
+char const *const Em("goink\\\031");
+char const *const Sub("goink\\\032");
+char const *const Esc("goink\\\033");
+char const *const Fs("goink\\\034");
+char const *const Gs("goink\\\035");
+char const *const Rs("goink\\\036");
+char const *const Us("goink\\\037");
+char const *const HexNonPrintable("\\\x03");
+char const *const Delete("\\\177");
+char const *const MultibyteSnowman("\xE2\x98\x83");
+// CHECK-FIXES: {{^}}char const *const MultibyteSnowman("\xE2\x98\x83");{{$}}
+
+char const *const TrailingSpace("A line \\with space. \n");
+char const *const TrailingNewLine("A single \\line.\n");
+char const *const AlreadyRaw(R"(foobie\\bletch)");
+char const *const UTF8Literal(u8"foobie\\bletch");
+char const *const UTF8RawLiteral(u8R"(foobie\\bletch)");
+// TODO: enable these tests once all supported compilers
+// support char16_t and char32_t (VS2013 does not)
+// char16_t const *const UTF16Literal(u"foobie\\bletch");
+// char16_t const *const UTF16RawLiteral(uR"(foobie\\bletch)");
+// char32_t const *const UTF32Literal(U"foobie\\bletch");
+// char32_t const *const UTF32RawLiteral(UR"(foobie\\bletch)");
+wchar_t const *const WideLiteral(L"foobie\\bletch");
+wchar_t const *const WideRawLiteral(LR"(foobie\\bletch)");
+
+char const *const SingleQuote("goink\'frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: {{.*}} can be written as a raw string literal
+// CHECK-XFIXES: {{^}}char const *const SingleQuote(R"(goink'frob)");{{$}}
+
+char const *const DoubleQuote("goink\"frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const DoubleQuote(R"(goink"frob)");{{$}}
+
+char const *const QuestionMark("goink\?frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const QuestionMark(R"(goink?frob)");{{$}}
+
+char const *const RegEx("goink\\(one|two\\)\\\\\\?.*\\nfrob");
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const RegEx(R"(goink\(one|two\)\\\?.*\nfrob)");{{$}}
+
+char const *const Path("C:\\Program Files\\Vendor\\Application\\Application.exe");
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const Path(R"(C:\Program Files\Vendor\Application\Application.exe)");{{$}}
+
+char const *const ContainsSentinel("who\\ops)\"");
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ContainsSentinel(R"lit(who\ops)")lit");{{$}}
+
+char const *const ContainsDelim("whoops)\")lit\"");
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ContainsDelim(R"lit1(whoops)")lit")lit1");{{$}}
+
+char const *const OctalPrintable("\100\\");
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const OctalPrintable(R"(@\)");{{$}}
+
+char const *const HexPrintable("\x40\\");
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const HexPrintable(R"(@\)");{{$}}
+
+char const *const prettyFunction(__PRETTY_FUNCTION__);
+char const *const function(__FUNCTION__);
+char const *const func(__func__);
+
+#define TRICK(arg_) #arg_
+char const *const MacroBody = TRICK(foo\\bar);
+
+#define HAT(rabbit_) #rabbit_ "foo\\bar"
+char const *const StringizedMacroArgument = HAT(foo\\bar);
+
+#define SUBST(lit_) lit_
+char const *const MacroArgument = SUBST("foo\\bar");
+// FIXME: We should be able to replace this string literal macro argument
+
+template <typename T>
+void fn(char const *const Arg) {
+ char const *const Str("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} char const *const Str(R"(foo\bar)");{{$}}
+}
+
+template <>
+void fn<int>(char const *const Arg) {
+ char const *const Str("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} char const *const Str(R"(foo\bar)");{{$}}
+}
+
+void callFn() {
+ fn<int>("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} fn<int>(R"(foo\bar)");{{$}}
+ fn<double>("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} fn<double>(R"(foo\bar)");{{$}}
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg-delayed.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg-delayed.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg-delayed.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg-delayed.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t -- -- -fdelayed-template-parsing
+
+int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}}int foo() {{{$}}
+ return 0;
+}
+
+template <class T>
+struct MyFoo {
+ int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}} int foo() {{{$}}
+ return 0;
+ }
+};
+// Explicit instantiation.
+template class MyFoo<int>;
+
+template <class T>
+struct MyBar {
+ // This declaration isn't instantiated and won't be parsed 'delayed-template-parsing'.
+ int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}} int foo() {{{$}}
+ return 0;
+ }
+};
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.c?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.c Fri Oct 11 05:05:42 2019
@@ -0,0 +1,58 @@
+// RUN: clang-tidy -checks=-*,modernize-redundant-void-arg %s -- -x c | count 0
+
+#define NULL 0
+
+extern int i;
+
+int foo2() {
+ return 0;
+}
+
+int j = 1;
+
+int foo(void) {
+ return 0;
+}
+
+typedef unsigned int my_uint;
+
+typedef void my_void;
+
+// A function taking void and returning a pointer to function taking void
+// and returning int.
+int (*returns_fn_void_int(void))(void);
+
+typedef int (*returns_fn_void_int_t(void))(void);
+
+int (*returns_fn_void_int(void))(void) {
+ return NULL;
+}
+
+// A function taking void and returning a pointer to a function taking void
+// and returning a pointer to a function taking void and returning void.
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void);
+
+typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void);
+
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void) {
+ return NULL;
+}
+
+void bar() {
+ int i;
+ int *pi = NULL;
+ void *pv = (void *) pi;
+ float f;
+ float *fi;
+ double d;
+ double *pd;
+}
+
+void (*f1)(void);
+void (*f2)(void) = NULL;
+void (*f3)(void) = bar;
+void (*fa)();
+void (*fb)() = NULL;
+void (*fc)() = bar;
+
+typedef void (function_ptr)(void);
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,558 @@
+// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t
+
+#define NULL 0
+
+int foo();
+
+void bar();
+
+void bar2();
+
+extern "C" void ecfoo(void);
+
+extern "C" void ecfoo(void) {
+}
+
+extern int i;
+
+int j = 1;
+
+int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}}int foo() {{{$}}
+ return 0;
+}
+
+typedef unsigned int my_uint;
+
+typedef void my_void;
+
+// A function taking void and returning a pointer to function taking void
+// and returning int.
+int (*returns_fn_void_int(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function declaration
+// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function declaration
+// CHECK-FIXES: {{^}}int (*returns_fn_void_int())();{{$}}
+
+typedef int (*returns_fn_void_int_t(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-2]]:44: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef int (*returns_fn_void_int_t())();{{$}}
+
+// Should work for type aliases as well as typedef.
+using returns_fn_void_int_t2 = int (*(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: {{.*}} in type alias
+// CHECK-MESSAGES: :[[@LINE-2]]:46: warning: {{.*}} in type alias
+// CHECK-FIXES: {{^}}using returns_fn_void_int_t2 = int (*())();{{$}}
+
+int (*returns_fn_void_int(void))(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function definition
+// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}int (*returns_fn_void_int())() {{{$}}
+ return nullptr;
+}
+
+// A function taking void and returning a pointer to a function taking void
+// and returning a pointer to a function taking void and returning void.
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function declaration
+// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function declaration
+// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function declaration
+// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())();{{$}}
+
+typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:52: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-2]]:59: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-3]]:66: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef void (*(*returns_fn_returns_fn_void_void_t())())();{{$}}
+
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function definition
+// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function definition
+// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())() {{{$}}
+ return nullptr;
+}
+
+void bar(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}void bar() {{{$}}
+}
+
+void op_fn(int i) {
+}
+
+class gronk {
+public:
+ gronk();
+ ~gronk();
+
+ void foo();
+ void bar();
+ void bar2
+ ();
+ void operation(int i) { }
+
+private:
+ int m_i;
+ int *m_pi;
+ float m_f;
+ float *m_pf;
+ double m_d;
+ double *m_pd;
+
+ void (*f1)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in field declaration
+ // CHECK-FIXES: {{^ }}void (*f1)();{{$}}
+
+ void (*op)(int i);
+
+ void (gronk::*p1)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in field declaration
+ // CHECK-FIXES: {{^ }}void (gronk::*p1)();{{$}}
+
+ int (gronk::*p_mi);
+
+ void (gronk::*p2)(int);
+
+ void (*(*returns_fn_returns_fn_void_void(void))(void))(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in function declaration
+ // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: {{.*}} in function declaration
+ // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: {{.*}} in function declaration
+ // CHECK-FIXES: {{^}} void (*(*returns_fn_returns_fn_void_void())())();{{$}}
+
+ void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)(void))(void))(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:58: warning: {{.*}} in field declaration
+ // CHECK-MESSAGES: :[[@LINE-2]]:65: warning: {{.*}} in field declaration
+ // CHECK-MESSAGES: :[[@LINE-3]]:72: warning: {{.*}} in field declaration
+ // CHECK-FIXES: {{^}} void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)())())();{{$}}
+};
+
+int i;
+int *pi;
+void *pv = (void *) pi;
+float f;
+float *fi;
+double d;
+double *pd;
+
+void (*f1)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration
+// CHECK-FIXES: {{^}}void (*f1)();{{$}}
+
+void (*f2)(void) = nullptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2)() = nullptr;{{$}}
+
+void (*f2b)(void)(nullptr);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2b)()(nullptr);{{$}}
+
+void (*f2c)(void){nullptr};
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2c)(){nullptr};{{$}}
+
+void (*f2d)(void) = NULL;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2d)() = NULL;{{$}}
+
+void (*f2e)(void)(NULL);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2e)()(NULL);{{$}}
+
+void (*f2f)(void){NULL};
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2f)(){NULL};{{$}}
+
+void (*f3)(void) = bar;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f3)() = bar;{{$}}
+
+void (*o1)(int i);
+void (*o2)(int i) = nullptr;
+void (*o3)(int i)(nullptr);
+void (*o4)(int i){nullptr};
+void (*o5)(int i) = NULL;
+void (*o6)(int i)(NULL);
+void (*o7)(int i){NULL};
+void (*o8)(int i) = op_fn;
+
+void (*fa)();
+
+void (*fb)() = nullptr;
+
+void (*fc)() = bar;
+
+typedef void (function_ptr)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef void (function_ptr)();{{$}}
+
+// intentionally not LLVM style to check preservation of whitesapce
+typedef void (function_ptr2)
+ (
+ void
+ );
+// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^typedef void \(function_ptr2\)$}}
+// CHECK-FIXES-NEXT: {{^ \($}}
+// CHECK-FIXES-NEXT: {{^ $}}
+// CHECK-FIXES-NEXT: {{^ \);$}}
+
+// intentionally not LLVM style to check preservation of whitesapce
+typedef
+void
+(
+*
+(
+*
+returns_fn_returns_fn_void_void_t2
+(
+void
+)
+)
+(
+void
+)
+)
+(
+void
+)
+;
+// CHECK-MESSAGES: :[[@LINE-11]]:1: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-8]]:1: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-5]]:1: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^typedef$}}
+// CHECK-FIXES-NEXT: {{^void$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NEXT: {{^\*$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NEXT: {{^\*$}}
+// CHECK-FIXES-NEXT: {{^returns_fn_returns_fn_void_void_t2$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NOT: {{[^ ]}}
+// CHECK-FIXES: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NOT: {{[^ ]}}
+// CHECK-FIXES: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NOT: {{[^ ]}}
+// CHECK-FIXES: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^;$}}
+
+
+void (gronk::*p1)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration
+// CHECK-FIXES: {{^}}void (gronk::*p1)();{{$}}
+
+void (gronk::*p2)(void) = &gronk::foo;
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (gronk::*p2)() = &gronk::foo;{{$}}
+
+typedef void (gronk::*member_function_ptr)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef void (gronk::*member_function_ptr)();{{$}}
+
+// intentionally not LLVM style to check preservation of whitesapce
+typedef void (gronk::*member_function_ptr2)
+ (
+ void
+ );
+// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^typedef void \(gronk::\*member_function_ptr2\)$}}
+// CHECK-FIXES-NEXT: {{^ \($}}
+// CHECK-FIXES-NEXT: {{^ $}}
+// CHECK-FIXES-NEXT: {{^ \);$}}
+
+void gronk::foo() {
+ void (*f1)(void) = &::bar;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-FIXES: {{^ }}void (*f1)() = &::bar;{{$}}
+
+ void (*f2)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (*f2)();{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f3)
+ (
+ void
+ );
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (*f3){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ \);$}}
+}
+
+void gronk::bar(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}void gronk::bar() {{{$}}
+ void (gronk::*p3)(void) = &gronk::foo;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration with initializer
+ // CHECK-FIXES: {{^ }}void (gronk::*p3)() = &gronk::foo;{{$}}
+
+ void (gronk::*p4)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (gronk::*p4)();{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (gronk::*p5)
+ (
+ void
+ );
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (gronk::*p5){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NExT: {{^ $}}
+ // CHECK-FIXES-NExT: {{^ \);$}}
+}
+
+// intentionally not LLVM style to check preservation of whitesapce
+void gronk::bar2
+ (
+ void
+ )
+// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^void gronk::bar2$}}
+// CHECK-FIXES-NEXT: {{^ \($}}
+// CHECK-FIXES-NEXT: {{^ $}}
+// CHECK-FIXES-NEXT: {{^ \)$}}
+{
+}
+
+gronk::gronk(void)
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}gronk::gronk(){{$}}
+ : f1(nullptr),
+ p1(nullptr) {
+}
+
+gronk::~gronk(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}gronk::~gronk() {{{$}}
+}
+
+class nutter {
+public:
+ nutter();
+};
+
+nutter::nutter(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}nutter::nutter() {{{$}}
+ void (*f3)(void) = static_cast<void (*)(void)>(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-2]]:43: warning: {{.*}} in named cast
+ // CHECK-FIXES: void (*f3)() = static_cast<void (*)()>(0);{{$}}
+
+ void (*f4)(void) = (void (*)(void)) 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: {{.*}} in cast expression
+ // CHECK-FIXES: void (*f4)() = (void (*)()) 0;{{$}}
+
+ void (*f5)(void) = reinterpret_cast<void (*)(void)>(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: {{.*}} in named cast
+ // CHECK-FIXES: void (*f5)() = reinterpret_cast<void (*)()>(0);{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f6)(void) = static_cast<void (*)
+ (
+ void
+ )>(0);
+ // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast
+ // CHECK-FIXES: {{^ }}void (*f6)() = static_cast<void (*){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ }})>(0);{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f7)(void) = (void (*)
+ (
+ void
+ )) 0;
+ // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in cast expression
+ // CHECK-FIXES: {{^ }}void (*f7)() = (void (*){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ \)\) 0;$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f8)(void) = reinterpret_cast<void (*)
+ (
+ void
+ )>(0);
+ // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast
+ // CHECK-FIXES: {{^ }}void (*f8)() = reinterpret_cast<void (*){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ \)>\(0\);$}}
+
+ void (*o1)(int) = static_cast<void (*)(int)>(0);
+ void (*o2)(int) = (void (*)(int)) 0;
+ void (*o3)(int) = reinterpret_cast<void (*)(int)>(0);
+}
+
+class generator {
+public:
+ int operator()(void) { return 1; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: {{.*}} in function definition
+ // CHECK-FIXES: {{^ }}int operator()() { return 1; }{{$}}
+};
+
+void test_lambda_functions() {
+ auto lamb_duh = [](void (*fn)(void)) { (*fn)(); };
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}auto lamb_duh = [](void (*fn)()) { (*fn)(); };{{$}}
+
+ auto lambda_generator = [](void) { return 1; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: {{.*}} in lambda expression
+ // CHECK-FIXES: {{^ }}auto lambda_generator = []() { return 1; };{{$}}
+
+ auto gen2 = []() { return 1; };
+
+ auto gen3 = []{ return 1; };
+
+ auto void_returner = [](void) -> void (*)(void) { return f1; };
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: {{.*}} in lambda expression
+ // CHECK-MESSAGES: [[@LINE-2]]:45: warning: {{.*}} in lambda expression
+ // CHECK-FIXES: {{^ }}auto void_returner = []() -> void (*)() { return f1; };{{$}}
+}
+
+#define M(x) x
+
+M(void inmacro(void) {})
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in function definition
+// CHECK-FIXES: M(void inmacro() {})
+
+#define F(A, B) \
+ struct F_##A##_##B { \
+ F_##A##_##B(void); \
+ }; \
+ F_##A##_##B::F_##A##_##B(void)
+
+F(Foo, Bar) {
+
+}
+
+struct DefinitionWithNoBody {
+ DefinitionWithNoBody(void) = delete;
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: {{.*}} in function definition
+ // CHECK-FIXES: DefinitionWithNoBody() = delete;
+};
+
+
+
+#define BODY {}
+#define LAMBDA1 [](void){}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+// CHECK-FIXES: LAMBDA1 [](){}
+
+#define LAMBDA2 [](void)BODY
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+// CHECK-FIXES: LAMBDA2 []()BODY
+
+#define LAMBDA3(captures, args, body) captures args body
+#define WRAP(...) __VA_ARGS__
+
+#define LAMBDA4 (void)LAMBDA3([],(void),BODY)
+// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+// CHECK-FIXES: LAMBDA4 (void)LAMBDA3([],(),BODY)
+
+#define LAMBDA5 []() -> void (*)(void) {return BODY;}
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+// CHECK-FIXES: LAMBDA5 []() -> void (*)() {return BODY;}
+void lambda_expression_with_macro_test(){
+ (void)LAMBDA1;
+ (void)LAMBDA2;
+ (void)LAMBDA3([], (void), BODY);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+ // CHECK-FIXES: (void)LAMBDA3([], (), BODY);
+
+ LAMBDA4;
+ LAMBDA5;
+ WRAP((void)WRAP(WRAP(LAMBDA3(WRAP([]), WRAP((void)), WRAP(BODY)))));
+ // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+ // CHECK-FIXES: WRAP((void)WRAP(WRAP(LAMBDA3(WRAP([]), WRAP(()), WRAP(BODY)))));
+
+ (void)WRAP([](void) {});
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+ // CHECK-FIXES: (void)WRAP([]() {});
+
+ [](void) BODY;
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant void argument list in lambda expression [modernize-redundant-void-arg]
+ // CHECK-FIXES: []() BODY;
+}
+
+namespace qqq {
+void foo() BODY
+void bar(void) BODY;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant void argument list in function definition
+// CHECK-FIXES: void bar() BODY;
+}
+
+struct S_1 {
+ void g_1(void) const {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+ // CHECK-FIXES: void g_1() const {
+ int a;
+ (void)a;
+ }
+
+ void g_2() const {
+ int a;
+ (void)a;
+ }
+};
+
+template <typename T0>
+struct S_2 {
+ void g_1(void) const {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+ // CHECK-FIXES: void g_1() const {
+ int a;
+ (void)a;
+ }
+
+ void g_2() const {
+ int a;
+ (void)a;
+ }
+};
+
+template <typename T0>
+struct S_3 {
+ template <typename T1>
+ void g_1(void) const {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+ // CHECK-FIXES: void g_1() const {
+ int a;
+ (void)a;
+ }
+ template <typename T2>
+ void g_2() const {
+ int a;
+ (void)a;
+ }
+};
+
+template <typename T1>
+void g_3(void) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+ // CHECK-FIXES: void g_3() {
+ int a;
+ (void)a;
+}
+
+//Template instantiation
+void f_testTemplate() {
+ S_1();
+ S_2<int>();
+ S_3<int>();
+ g_3<int>();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-auto-ptr.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-auto-ptr.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-auto-ptr.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-auto-ptr.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,303 @@
+// RUN: %check_clang_tidy %s modernize-replace-auto-ptr %t -- -- -I %S/Inputs/modernize-replace-auto-ptr
+
+// CHECK-FIXES: #include <utility>
+
+#include "memory.h"
+
+// Instrumentation for auto_ptr_ref test.
+struct Base {};
+struct Derived : Base {};
+std::auto_ptr<Derived> create_derived_ptr();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated, use unique_ptr instead [modernize-replace-auto-ptr]
+// CHECK-FIXES: std::unique_ptr<Derived> create_derived_ptr();
+
+
+// Test function return values (declaration)
+std::auto_ptr<char> f_5();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated
+// CHECK-FIXES: std::unique_ptr<char> f_5()
+
+
+// Test function parameters.
+void f_6(std::auto_ptr<int>);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated
+// CHECK-FIXES: void f_6(std::unique_ptr<int>);
+void f_7(const std::auto_ptr<int> &);
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: auto_ptr is deprecated
+// CHECK-FIXES: void f_7(const std::unique_ptr<int> &);
+
+
+// Test on record type fields.
+struct A {
+ std::auto_ptr<int> field;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> field;
+
+ typedef std::auto_ptr<int> int_ptr_type;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: auto_ptr is deprecated
+ // CHECK-FIXES: typedef std::unique_ptr<int> int_ptr_type;
+};
+
+
+// FIXME: Test template WITH instantiation.
+template <typename T> struct B {
+ typedef typename std::auto_ptr<T> created_type;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: auto_ptr is deprecated
+ // CHECK-FIXES: typedef typename std::unique_ptr<T> created_type;
+
+ created_type create() { return std::auto_ptr<T>(new T()); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: auto_ptr is deprecated
+ // CHECK-FIXES: created_type create() { return std::unique_ptr<T>(new T()); }
+};
+
+
+// Test 'using' in a namespace (declaration)
+namespace ns_1 {
+// Test multiple using declarations.
+ using std::auto_ptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: using std::unique_ptr;
+ using std::auto_ptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: using std::unique_ptr;
+}
+
+
+namespace ns_2 {
+template <typename T> struct auto_ptr {};
+}
+
+void f_1() {
+ std::auto_ptr<int> a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> a;
+
+ // Check that spaces aren't modified unnecessarily.
+ std:: auto_ptr <int> b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std:: unique_ptr <int> b;
+ std :: auto_ptr < char > c(new char());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std :: unique_ptr < char > c(new char());
+
+ // Test construction from a temporary.
+ std::auto_ptr<char> d = std::auto_ptr<char>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<char> d = std::unique_ptr<char>();
+
+ typedef std::auto_ptr<int> int_ptr_t;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: auto_ptr is deprecated
+ // CHECK-FIXES: typedef std::unique_ptr<int> int_ptr_t;
+ int_ptr_t e(new int());
+
+ // Test pointers.
+ std::auto_ptr<int> *f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> *f;
+
+ // Test 'static' declarations.
+ static std::auto_ptr<int> g;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated
+ // CHECK-FIXES: static std::unique_ptr<int> g;
+
+ // Test with cv-qualifiers.
+ const std::auto_ptr<int> h;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: const std::unique_ptr<int> h;
+ volatile std::auto_ptr<int> i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated
+ // CHECK-FIXES: volatile std::unique_ptr<int> i;
+ const volatile std::auto_ptr<int> j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: auto_ptr is deprecated
+ // CHECK-FIXES: const volatile std::unique_ptr<int> j;
+
+ // Test auto and initializer-list.
+ auto k = std::auto_ptr<int>{};
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated
+ // CHECK-FIXES: auto k = std::unique_ptr<int>{};
+ std::auto_ptr<int> l{std::auto_ptr<int>()};
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> l{std::unique_ptr<int>()};
+
+ // Test interlocked auto_ptr.
+ std::auto_ptr<std::auto_ptr<int> > m;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<std::unique_ptr<int> > m;
+
+ // Test temporaries.
+ std::auto_ptr<char>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<char>();
+
+ // Test void-specialization.
+ std::auto_ptr<void> n;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<void> n;
+
+ // Test template WITH instantiation (instantiation).
+ B<double> o;
+ std::auto_ptr<double> p(o.create());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<double> p(o.create());
+
+ // Test 'using' in a namespace ("definition").
+ ns_1::auto_ptr<int> q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: auto_ptr is deprecated
+ // CHECK-FIXES: ns_1::unique_ptr<int> q;
+
+ // Test construction with an 'auto_ptr_ref'.
+ std::auto_ptr<Base> r(create_derived_ptr());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<Base> r(create_derived_ptr());
+}
+
+// Test without the nested name specifiers.
+void f_2() {
+ using namespace std;
+
+ auto_ptr<int> a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: auto_ptr is deprecated
+ // CHECK-FIXES: unique_ptr<int> a;
+}
+
+// Test using declaration.
+void f_3() {
+ using std::auto_ptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: using std::unique_ptr;
+
+ auto_ptr<int> a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: auto_ptr is deprecated
+ // CHECK-FIXES: unique_ptr<int> a;
+}
+
+// Test messing-up with macros.
+void f_4() {
+#define MACRO_1 <char>
+ std::auto_ptr MACRO_1 p(new char());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr MACRO_1 p(new char());
+#define MACRO_2 auto_ptr
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated
+ // CHECK-FIXES: #define MACRO_2 unique_ptr
+ std::MACRO_2<int> q;
+#define MACRO_3(Type) std::auto_ptr<Type>
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: auto_ptr is deprecated
+ // CHECK-FIXES: #define MACRO_3(Type) std::unique_ptr<Type>
+ MACRO_3(float)r(new float());
+#define MACRO_4 std::auto_ptr
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: auto_ptr is deprecated
+ // CHECK-FIXES: #define MACRO_4 std::unique_ptr
+ using MACRO_4;
+#undef MACRO_1
+#undef MACRO_2
+#undef MACRO_3
+#undef MACRO_4
+}
+
+// Test function return values (definition).
+std::auto_ptr<char> f_5()
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<char> f_5()
+{
+ // Test constructor.
+ return std::auto_ptr<char>(new char());
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated
+ // CHECK-FIXES: return std::unique_ptr<char>(new char());
+}
+
+// Test that non-std auto_ptr aren't replaced.
+void f_8() {
+ ns_2::auto_ptr<char> a;
+ using namespace ns_2;
+ auto_ptr<int> b;
+}
+
+// Fail to modify when the template is never instantiated.
+//
+// This might not be an issue. If it's never used it doesn't really matter if
+// it's changed or not. If it's a header and one of the source use it, then it
+// will still be changed.
+template <typename X>
+void f() {
+ std::auto_ptr<X> p;
+}
+
+// FIXME: Alias template could be replaced if a matcher existed.
+namespace std {
+template <typename T> using aaaaaaaa = auto_ptr<T>;
+}
+
+// We want to avoid replacing 'aaaaaaaa' by unique_ptr here. It's better to
+// change the type alias directly.
+std::aaaaaaaa<int> d;
+
+
+void takes_ownership_fn(std::auto_ptr<int> x);
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: auto_ptr is deprecated
+// CHECK-FIXES: void takes_ownership_fn(std::unique_ptr<int> x);
+
+std::auto_ptr<int> get_by_value();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated
+// CHECK-FIXES: std::unique_ptr<int> get_by_value();
+
+class Wrapper {
+ public:
+ std::auto_ptr<int> &get_wrapped();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+
+ private:
+ std::auto_ptr<int> wrapped;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+};
+
+void f() {
+ std::auto_ptr<int> a, b, c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> a, b, c;
+ Wrapper wrapper_a, wrapper_b;
+
+ a = b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::move to transfer ownership
+ // CHECK-FIXES: a = std::move(b);
+
+ wrapper_a.get_wrapped() = wrapper_b.get_wrapped();
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::move to transfer ownership
+ // CHECK-FIXES: wrapper_a.get_wrapped() = std::move(wrapper_b.get_wrapped());
+
+ // Test that 'std::move()' is inserted when call to the
+ // copy-constructor are made.
+ takes_ownership_fn(c);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::move to transfer ownership
+ // CHECK-FIXES: takes_ownership_fn(std::move(c));
+ takes_ownership_fn(wrapper_a.get_wrapped());
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::move to transfer ownership
+ // CHECK-FIXES: takes_ownership_fn(std::move(wrapper_a.get_wrapped()));
+
+ std::auto_ptr<int> d[] = { std::auto_ptr<int>(new int(1)),
+ std::auto_ptr<int>(new int(2)) };
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-3]]:35: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-3]]:35: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> d[] = { std::unique_ptr<int>(new int(1)),
+ // CHECK-FIXES-NEXT: std::unique_ptr<int>(new int(2)) };
+ std::auto_ptr<int> e = d[0];
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: use std::move to transfer ownership
+ // CHECK: std::unique_ptr<int> e = std::move(d[0]);
+
+ // Test that std::move() is not used when assigning an rvalue
+ std::auto_ptr<int> f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> f;
+ f = std::auto_ptr<int>(new int(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: auto_ptr is deprecated
+ // CHECK-NEXT: f = std::unique_ptr<int>(new int(0));
+
+ std::auto_ptr<int> g = get_by_value();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> g = get_by_value();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-random-shuffle.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-random-shuffle.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-random-shuffle.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-replace-random-shuffle.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s modernize-replace-random-shuffle %t
+
+//CHECK-FIXES: #include <random>
+
+namespace std {
+template <typename T> struct vec_iterator {
+ T *ptr;
+ vec_iterator operator++(int);
+};
+
+template <typename T> struct vector {
+ typedef vec_iterator<T> iterator;
+
+ iterator begin();
+ iterator end();
+};
+
+template <typename FwIt>
+void random_shuffle(FwIt begin, FwIt end);
+
+template <typename FwIt, typename randomFunc>
+void random_shuffle(FwIt begin, FwIt end, randomFunc& randomfunc);
+
+template <typename FwIt>
+void shuffle(FwIt begin, FwIt end);
+} // namespace std
+
+// Random Func
+int myrandom (int i) { return i;}
+
+using namespace std;
+
+int main() {
+ std::vector<int> vec;
+
+ std::random_shuffle(vec.begin(), vec.end());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' instead
+ // CHECK-FIXES: std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ std::shuffle(vec.begin(), vec.end());
+
+ random_shuffle(vec.begin(), vec.end());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' instead
+ // CHECK-FIXES: shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ std::random_shuffle(vec.begin(), vec.end(), myrandom);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' and an alternative random mechanism instead
+ // CHECK-FIXES: std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ random_shuffle(vec.begin(), vec.end(), myrandom);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' and an alternative random mechanism instead
+ // CHECK-FIXES: shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ shuffle(vec.begin(), vec.end());
+
+ return 0;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-return-braced-init-list.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-return-braced-init-list.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-return-braced-init-list.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-return-braced-init-list.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,199 @@
+// RUN: %check_clang_tidy -std=c++14 %s modernize-return-braced-init-list %t
+// FIXME: Fix the checker to work in C++17 mode.
+
+namespace std {
+typedef decltype(sizeof(int)) size_t;
+
+// libc++'s implementation
+template <class _E>
+class initializer_list {
+ const _E *__begin_;
+ size_t __size_;
+
+ initializer_list(const _E *__b, size_t __s)
+ : __begin_(__b),
+ __size_(__s) {}
+
+public:
+ typedef _E value_type;
+ typedef const _E &reference;
+ typedef const _E &const_reference;
+ typedef size_t size_type;
+
+ typedef const _E *iterator;
+ typedef const _E *const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const { return __size_; }
+ const _E *begin() const { return __begin_; }
+ const _E *end() const { return __begin_ + __size_; }
+};
+
+template <typename T>
+class vector {
+public:
+ vector(T) {}
+ vector(std::initializer_list<T>) {}
+};
+}
+
+class Bar {};
+
+Bar b0;
+
+class Foo {
+public:
+ Foo(Bar) {}
+ explicit Foo(Bar, unsigned int) {}
+ Foo(unsigned int) {}
+};
+
+class Baz {
+public:
+ Foo m() {
+ Bar bm;
+ return Foo(bm);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: avoid repeating the return type from the declaration; use a braced initializer list instead [modernize-return-braced-init-list]
+ // CHECK-FIXES: return {bm};
+ }
+};
+
+class Quux : public Foo {
+public:
+ Quux(Bar bar) : Foo(bar) {}
+ Quux(unsigned, unsigned, unsigned k = 0) : Foo(k) {}
+};
+
+Foo f() {
+ Bar b1;
+ return Foo(b1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {b1};
+}
+
+Foo f2() {
+ Bar b2;
+ return {b2};
+}
+
+auto f3() {
+ Bar b3;
+ return Foo(b3);
+}
+
+#define A(b) Foo(b)
+
+Foo f4() {
+ Bar b4;
+ return A(b4);
+}
+
+Foo f5() {
+ Bar b5;
+ return Quux(b5);
+}
+
+Foo f6() {
+ Bar b6;
+ return Foo(b6, 1);
+}
+
+std::vector<int> f7() {
+ int i7 = 1;
+ return std::vector<int>(i7);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+}
+
+Bar f8() {
+ return {};
+}
+
+Bar f9() {
+ return Bar();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+}
+
+Bar f10() {
+ return Bar{};
+}
+
+Foo f11(Bar b11) {
+ return Foo(b11);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {b11};
+}
+
+Foo f12() {
+ return f11(Bar());
+}
+
+Foo f13() {
+ return Foo(Bar()); // 13
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {Bar()}; // 13
+}
+
+Foo f14() {
+ // FIXME: Type narrowing should not occur!
+ return Foo(-1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {-1};
+}
+
+Foo f15() {
+ return Foo(f10());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {f10()};
+}
+
+Quux f16() {
+ return Quux(1, 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {1, 2};
+}
+
+Quux f17() {
+ return Quux(1, 2, 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {1, 2, 3};
+}
+
+template <typename T>
+T f19() {
+ return T();
+}
+
+Bar i1 = f19<Bar>();
+Baz i2 = f19<Baz>();
+
+template <typename T>
+Foo f20(T t) {
+ return Foo(t);
+}
+
+Foo i3 = f20(b0);
+
+template <typename T>
+class BazT {
+public:
+ T m() {
+ Bar b;
+ return T(b);
+ }
+
+ Foo m2(T t) {
+ return Foo(t);
+ }
+};
+
+BazT<Foo> bazFoo;
+Foo i4 = bazFoo.m();
+Foo i5 = bazFoo.m2(b0);
+
+BazT<Quux> bazQuux;
+Foo i6 = bazQuux.m();
+Foo i7 = bazQuux.m2(b0);
+
+auto v1 = []() { return std::vector<int>({1, 2}); }();
+auto v2 = []() -> std::vector<int> { return std::vector<int>({1, 2}); }();
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-shrink-to-fit.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-shrink-to-fit.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-shrink-to-fit.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-shrink-to-fit.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,87 @@
+// RUN: %check_clang_tidy %s modernize-shrink-to-fit %t
+
+namespace std {
+template <typename T> struct vector { void swap(vector &other); };
+}
+
+void f() {
+ std::vector<int> v;
+
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should be used to reduce the capacity of a shrinkable container [modernize-shrink-to-fit]
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ std::vector<int> &vref = v;
+ std::vector<int>(vref).swap(vref);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}vref.shrink_to_fit();{{$}}
+
+ std::vector<int> *vptr = &v;
+ std::vector<int>(*vptr).swap(*vptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}vptr->shrink_to_fit();{{$}}
+}
+
+struct X {
+ std::vector<int> v;
+ void f() {
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ std::vector<int> *vptr = &v;
+ std::vector<int>(*vptr).swap(*vptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}vptr->shrink_to_fit();{{$}}
+ }
+};
+
+template <typename T> void g() {
+ std::vector<int> v;
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ std::vector<T> v2;
+ std::vector<T>(v2).swap(v2);
+ // CHECK-FIXES: {{^ }}std::vector<T>(v2).swap(v2);{{$}}
+}
+
+template <typename T> void g2() {
+ std::vector<int> v;
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ T v3;
+ T(v3).swap(v3);
+ // CHECK-FIXES: {{^ }}T(v3).swap(v3);{{$}}
+}
+
+#define COPY_AND_SWAP_INT_VEC(x) std::vector<int>(x).swap(x)
+// CHECK-FIXES: #define COPY_AND_SWAP_INT_VEC(x) std::vector<int>(x).swap(x)
+
+void h() {
+ g<int>();
+ g<double>();
+ g<bool>();
+ g2<std::vector<int>>();
+ std::vector<int> v;
+ COPY_AND_SWAP_INT_VEC(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}COPY_AND_SWAP_INT_VEC(v);{{$}}
+}
+
+void PR38315() {
+ typedef std::vector<int> Vector;
+ Vector v;
+ Vector(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ using Vector2 = std::vector<int>;
+ Vector2 v2;
+ Vector2(v2).swap(v2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v2.shrink_to_fit();{{$}}
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-unary-static-assert.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-unary-static-assert.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-unary-static-assert.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-unary-static-assert.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-unary-static-assert %t
+
+#define FOO static_assert(sizeof(a) <= 15, "");
+#define MSG ""
+
+void f_textless(int a) {
+ static_assert(sizeof(a) <= 10, "");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when the string literal is an empty string [modernize-unary-static-assert]
+ // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 10 );{{$}}
+ static_assert(sizeof(a) <= 12, L"");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when
+ // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 12 );{{$}}
+ FOO
+ // CHECK-FIXES: {{^}} FOO{{$}}
+ static_assert(sizeof(a) <= 17, MSG);
+ // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 17, MSG);{{$}}
+}
+
+void f_with_tex(int a) {
+ static_assert(sizeof(a) <= 10, "Size of variable a is out of range!");
+}
+
+void f_unary(int a) { static_assert(sizeof(a) <= 10); }
+
+void f_incorrect_assert() { static_assert(""); }
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast-remove-stars.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast-remove-stars.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast-remove-stars.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast-remove-stars.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,233 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: '1'} , {key: modernize-use-auto.MinTypeNameLength, value: '0'}]}" \
+// RUN: -- -frtti
+
+struct A {
+ virtual ~A() {}
+};
+
+struct B : public A {};
+
+struct C {};
+
+void f_static_cast() {
+ long l = 1;
+ int i1 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = static_cast<int>(l);
+
+ const int i2 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto i2 = static_cast<int>(l);
+
+ long long ll = static_cast<long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ll = static_cast<long long>(l);
+ unsigned long long ull = static_cast<unsigned long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ull = static_cast<unsigned long long>(l);
+ unsigned int ui = static_cast<unsigned int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ui = static_cast<unsigned int>(l);
+ long double ld = static_cast<long double>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ld = static_cast<long double>(l);
+
+ A *a = new B();
+ B *b1 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = static_cast<B *>(a);
+
+ B *const b2 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto const b2 = static_cast<B *>(a);
+
+ const B *b3 = static_cast<const B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto b3 = static_cast<const B *>(a);
+
+ B &b4 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = static_cast<B &>(*a);
+
+ const B &b5 = static_cast<const B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b5 = static_cast<const B &>(*a);
+
+ B &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+
+ // Don't warn when non-cast involved
+ long double cast = static_cast<long double>(l), noncast = 5;
+
+ // Don't warn when auto is already being used.
+ auto i3 = static_cast<int>(l);
+ auto *b8 = static_cast<B *>(a);
+ auto &b9 = static_cast<B &>(*a);
+}
+
+void f_dynamic_cast() {
+ A *a = new B();
+ B *b1 = dynamic_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = dynamic_cast<B *>(a);
+
+ B &b2 = dynamic_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = dynamic_cast<B &>(*a);
+}
+
+void f_reinterpret_cast() {
+ auto *a = new A();
+ C *c1 = reinterpret_cast<C *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto c1 = reinterpret_cast<C *>(a);
+
+ C &c2 = reinterpret_cast<C &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = reinterpret_cast<C &>(*a);
+}
+
+void f_const_cast() {
+ const A *a1 = new A();
+ A *a2 = const_cast<A *>(a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto a2 = const_cast<A *>(a1);
+ A &a3 = const_cast<A &>(*a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &a3 = const_cast<A &>(*a1);
+}
+
+typedef unsigned char xmlChar;
+#define BAD_CAST (xmlChar *)
+
+#define XMLCHAR_CAST(x) (xmlChar *)(x)
+
+#define CAST_IN_MACRO(x) \
+ do { \
+ xmlChar *s = (xmlChar *)(x); \
+ } while (false);
+// CHECK-FIXES: xmlChar *s = (xmlChar *)(x);
+
+void f_cstyle_cast() {
+ auto *a = new A();
+ C *c1 = (C *)a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto c1 = (C *)a;
+
+ C &c2 = (C &)*a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = (C &)*a;
+
+ xmlChar *s = BAD_CAST "xml";
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto s = BAD_CAST "xml";
+ xmlChar *t = XMLCHAR_CAST("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto t = XMLCHAR_CAST("xml");
+ CAST_IN_MACRO("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+}
+
+void f_functional_cast() {
+ long l = 1;
+ int i1 = int(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = int(l);
+
+ B b;
+ A a = A(b);
+}
+
+class StringRef
+{
+public:
+ StringRef(const char *);
+ const char *begin() const;
+ const char *end() const;
+};
+
+template <typename T, typename U>
+T template_value_cast(const U &u);
+
+template <typename T, typename U>
+T *template_pointer_cast(U *u);
+
+template <typename T, typename U>
+T &template_reference_cast(U &u);
+
+template <typename T, typename U>
+const T *template_const_pointer_cast(const U *u);
+
+template <typename T, typename U>
+const T &template_const_reference_cast(const U &u);
+
+template <typename T>
+T template_value_get(StringRef s);
+
+struct S {
+ template <typename T>
+ const T *template_member_get();
+};
+
+template <typename T>
+T max(T t1, T t2);
+
+void f_template_cast()
+{
+ double d = 0;
+ int i1 = template_value_cast<int>(d);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = template_value_cast<int>(d);
+
+ A *a = new B();
+ B *b1 = template_value_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = template_value_cast<B *>(a);
+ B &b2 = template_value_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = template_value_cast<B &>(*a);
+ B *b3 = template_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b3 = template_pointer_cast<B>(a);
+ B &b4 = template_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = template_reference_cast<B>(*a);
+ const B *b5 = template_const_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto b5 = template_const_pointer_cast<B>(a);
+ const B &b6 = template_const_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b6 = template_const_reference_cast<B>(*a);
+ B *b7 = template_value_get<B *>("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b7 = template_value_get<B *>("foo");
+ B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b8 = template_value_get<B *>("foo"), b9 = template_value_get<B *>("bar");
+
+ S s;
+ const B *b10 = s.template_member_get<B>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto b10 = s.template_member_get<B>();
+
+ // Don't warn when auto is already being used.
+ auto i2 = template_value_cast<int>(d);
+ auto *i3 = template_value_cast<int *>(d);
+ auto **i4 = template_value_cast<int **>(d);
+ auto &i5 = template_reference_cast<int>(d);
+
+ // Don't warn for implicit template arguments.
+ int i6 = max(i1, i2);
+
+ // Don't warn for mismatched var and initializer types.
+ A *a1 = template_value_cast<B *>(a);
+
+ // Don't warn for mismatched var types.
+ B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar");
+
+ // Don't warn for implicit variables.
+ for (auto &c : template_reference_cast<StringRef>(*a)) {
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-cast.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,233 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '0'}]}" \
+// RUN: -- -I %S/Inputs/modernize-use-auto -frtti
+
+struct A {
+ virtual ~A() {}
+};
+
+struct B : public A {};
+
+struct C {};
+
+void f_static_cast() {
+ long l = 1;
+ int i1 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = static_cast<int>(l);
+
+ const int i2 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto i2 = static_cast<int>(l);
+
+ long long ll = static_cast<long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ll = static_cast<long long>(l);
+ unsigned long long ull = static_cast<unsigned long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ull = static_cast<unsigned long long>(l);
+ unsigned int ui = static_cast<unsigned int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ui = static_cast<unsigned int>(l);
+ long double ld = static_cast<long double>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ld = static_cast<long double>(l);
+
+ A *a = new B();
+ B *b1 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = static_cast<B *>(a);
+
+ B *const b2 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *const b2 = static_cast<B *>(a);
+
+ const B *b3 = static_cast<const B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto *b3 = static_cast<const B *>(a);
+
+ B &b4 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = static_cast<B &>(*a);
+
+ const B &b5 = static_cast<const B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b5 = static_cast<const B &>(*a);
+
+ B &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+
+ // Don't warn when non-cast involved
+ long double cast = static_cast<long double>(l), noncast = 5;
+
+ // Don't warn when auto is already being used.
+ auto i3 = static_cast<int>(l);
+ auto *b8 = static_cast<B *>(a);
+ auto &b9 = static_cast<B &>(*a);
+}
+
+void f_dynamic_cast() {
+ A *a = new B();
+ B *b1 = dynamic_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = dynamic_cast<B *>(a);
+
+ B &b2 = dynamic_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = dynamic_cast<B &>(*a);
+}
+
+void f_reinterpret_cast() {
+ auto *a = new A();
+ C *c1 = reinterpret_cast<C *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *c1 = reinterpret_cast<C *>(a);
+
+ C &c2 = reinterpret_cast<C &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = reinterpret_cast<C &>(*a);
+}
+
+void f_const_cast() {
+ const A *a1 = new A();
+ A *a2 = const_cast<A *>(a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *a2 = const_cast<A *>(a1);
+ A &a3 = const_cast<A &>(*a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &a3 = const_cast<A &>(*a1);
+}
+
+typedef unsigned char xmlChar;
+#define BAD_CAST (xmlChar *)
+
+#define XMLCHAR_CAST(x) (xmlChar *)(x)
+
+#define CAST_IN_MACRO(x) \
+ do { \
+ xmlChar *s = (xmlChar *)(x); \
+ } while (false);
+// CHECK-FIXES: xmlChar *s = (xmlChar *)(x);
+
+void f_cstyle_cast() {
+ auto *a = new A();
+ C *c1 = (C *)a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *c1 = (C *)a;
+
+ C &c2 = (C &)*a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = (C &)*a;
+
+ xmlChar *s = BAD_CAST "xml";
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *s = BAD_CAST "xml";
+ xmlChar *t = XMLCHAR_CAST("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *t = XMLCHAR_CAST("xml");
+ CAST_IN_MACRO("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+}
+
+void f_functional_cast() {
+ long l = 1;
+ int i1 = int(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = int(l);
+
+ B b;
+ A a = A(b);
+}
+
+class StringRef
+{
+public:
+ StringRef(const char *);
+ const char *begin() const;
+ const char *end() const;
+};
+
+template <typename T, typename U>
+T template_value_cast(const U &u);
+
+template <typename T, typename U>
+T *template_pointer_cast(U *u);
+
+template <typename T, typename U>
+T &template_reference_cast(U &u);
+
+template <typename T, typename U>
+const T *template_const_pointer_cast(const U *u);
+
+template <typename T, typename U>
+const T &template_const_reference_cast(const U &u);
+
+template <typename T>
+T template_value_get(StringRef s);
+
+struct S {
+ template <typename T>
+ const T *template_member_get();
+};
+
+template <typename T>
+T max(T t1, T t2);
+
+void f_template_cast()
+{
+ double d = 0;
+ int i1 = template_value_cast<int>(d);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = template_value_cast<int>(d);
+
+ A *a = new B();
+ B *b1 = template_value_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = template_value_cast<B *>(a);
+ B &b2 = template_value_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = template_value_cast<B &>(*a);
+ B *b3 = template_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b3 = template_pointer_cast<B>(a);
+ B &b4 = template_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = template_reference_cast<B>(*a);
+ const B *b5 = template_const_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto *b5 = template_const_pointer_cast<B>(a);
+ const B &b6 = template_const_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b6 = template_const_reference_cast<B>(*a);
+ B *b7 = template_value_get<B *>("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b7 = template_value_get<B *>("foo");
+ B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+
+ S s;
+ const B *b10 = s.template_member_get<B>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto *b10 = s.template_member_get<B>();
+
+ // Don't warn when auto is already being used.
+ auto i2 = template_value_cast<int>(d);
+ auto *i3 = template_value_cast<int *>(d);
+ auto **i4 = template_value_cast<int **>(d);
+ auto &i5 = template_reference_cast<int>(d);
+
+ // Don't warn for implicit template arguments.
+ int i6 = max(i1, i2);
+
+ // Don't warn for mismatched var and initializer types.
+ A *a1 = template_value_cast<B *>(a);
+
+ // Don't warn for mismatched var types.
+ B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar");
+
+ // Don't warn for implicit variables.
+ for (auto &c : template_reference_cast<StringRef>(*a)) {
+ }
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-iterator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-iterator.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-iterator.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-iterator.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,320 @@
+// RUN: %check_clang_tidy -std=c++11,c++14 %s modernize-use-auto %t -- -- -I %S/Inputs/modernize-use-auto
+// FIXME: Fix the checker to work in C++17 mode.
+
+#include "containers.h"
+
+void f_array() {
+ std::array<int, 4> C;
+ std::array<int, 4>::iterator ArrayI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators [modernize-use-auto]
+ // CHECK-FIXES: auto ArrayI1 = C.begin();
+
+ std::array<int, 5>::reverse_iterator ArrayI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ArrayI2 = C.rbegin();
+
+ const std::array<int, 3> D;
+ std::array<int, 3>::const_iterator ArrayI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ArrayI3 = D.begin();
+
+ std::array<int, 5>::const_reverse_iterator ArrayI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ArrayI4 = D.rbegin();
+}
+
+void f_deque() {
+ std::deque<int> C;
+ std::deque<int>::iterator DequeI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI1 = C.begin();
+
+ std::deque<int>::reverse_iterator DequeI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI2 = C.rbegin();
+
+ const std::deque<int> D;
+ std::deque<int>::const_iterator DequeI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI3 = D.begin();
+
+ std::deque<int>::const_reverse_iterator DequeI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI4 = D.rbegin();
+}
+
+void f_forward_list() {
+ std::forward_list<int> C;
+ std::forward_list<int>::iterator FListI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto FListI1 = C.begin();
+
+ const std::forward_list<int> D;
+ std::forward_list<int>::const_iterator FListI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto FListI2 = D.begin();
+}
+
+void f_list() {
+ std::list<int> C;
+ std::list<int>::iterator ListI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI1 = C.begin();
+ std::list<int>::reverse_iterator ListI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI2 = C.rbegin();
+
+ const std::list<int> D;
+ std::list<int>::const_iterator ListI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI3 = D.begin();
+ std::list<int>::const_reverse_iterator ListI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI4 = D.rbegin();
+}
+
+void f_vector() {
+ std::vector<int> C;
+ std::vector<int>::iterator VecI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI1 = C.begin();
+
+ std::vector<int>::reverse_iterator VecI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI2 = C.rbegin();
+
+ const std::vector<int> D;
+ std::vector<int>::const_iterator VecI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI3 = D.begin();
+
+ std::vector<int>::const_reverse_iterator VecI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI4 = D.rbegin();
+}
+
+void f_map() {
+ std::map<int, int> C;
+ std::map<int, int>::iterator MapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI1 = C.begin();
+
+ std::map<int, int>::reverse_iterator MapI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI2 = C.rbegin();
+
+ const std::map<int, int> D;
+ std::map<int, int>::const_iterator MapI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI3 = D.begin();
+
+ std::map<int, int>::const_reverse_iterator MapI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI4 = D.rbegin();
+}
+
+void f_multimap() {
+ std::multimap<int, int> C;
+ std::multimap<int, int>::iterator MMapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI1 = C.begin();
+
+ std::multimap<int, int>::reverse_iterator MMapI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI2 = C.rbegin();
+
+ const std::multimap<int, int> D;
+ std::multimap<int, int>::const_iterator MMapI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI3 = D.begin();
+
+ std::multimap<int, int>::const_reverse_iterator MMapI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI4 = D.rbegin();
+}
+
+void f_set() {
+ std::set<int> C;
+ std::set<int>::iterator SetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI1 = C.begin();
+
+ std::set<int>::reverse_iterator SetI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI2 = C.rbegin();
+
+ const std::set<int> D;
+ std::set<int>::const_iterator SetI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI3 = D.begin();
+
+ std::set<int>::const_reverse_iterator SetI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI4 = D.rbegin();
+}
+
+void f_multiset() {
+ std::multiset<int> C;
+ std::multiset<int>::iterator MSetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI1 = C.begin();
+
+ std::multiset<int>::reverse_iterator MSetI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI2 = C.rbegin();
+
+ const std::multiset<int> D;
+ std::multiset<int>::const_iterator MSetI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI3 = D.begin();
+
+ std::multiset<int>::const_reverse_iterator MSetI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI4 = D.rbegin();
+}
+
+void f_unordered_map() {
+ std::unordered_map<int, int> C;
+ std::unordered_map<int, int>::iterator UMapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMapI1 = C.begin();
+
+ const std::unordered_map<int, int> D;
+ std::unordered_map<int, int>::const_iterator UMapI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMapI2 = D.begin();
+}
+
+void f_unordered_multimap() {
+ std::unordered_multimap<int, int> C;
+ std::unordered_multimap<int, int>::iterator UMMapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMMapI1 = C.begin();
+
+ const std::unordered_multimap<int, int> D;
+ std::unordered_multimap<int, int>::const_iterator UMMapI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMMapI2 = D.begin();
+}
+
+void f_unordered_set() {
+ std::unordered_set<int> C;
+ std::unordered_set<int>::iterator USetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto USetI1 = C.begin();
+
+ const std::unordered_set<int> D;
+ std::unordered_set<int>::const_iterator USetI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto USetI2 = D.begin();
+}
+
+void f_unordered_multiset() {
+ std::unordered_multiset<int> C;
+ std::unordered_multiset<int>::iterator UMSetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMSetI1 = C.begin();
+
+ const std::unordered_multiset<int> D;
+ std::unordered_multiset<int>::const_iterator UMSetI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMSetI2 = D.begin();
+}
+
+typedef std::vector<int>::iterator int_iterator;
+
+std::vector<int> Vec;
+std::unordered_map<int, int> Map;
+
+void sugar() {
+ // Types with more sugar should work. Types with less should not.
+ int_iterator more_sugar = Vec.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto more_sugar = Vec.begin();
+}
+
+void initializer_list() {
+ // Initialization from initializer lists isn't allowed. Using 'auto' would
+ // result in std::initializer_list being deduced for the type.
+ std::unordered_map<int, int>::iterator I{Map.begin()};
+ std::unordered_map<int, int>::iterator I2 = {Map.begin()};
+}
+
+void construction() {
+ // Various forms of construction. Default constructors and constructors with
+ // all-default parameters shouldn't get transformed. Construction from other
+ // types is also not allowed.
+
+ std::unordered_map<int, int>::iterator copy(Map.begin());
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto copy(Map.begin());
+
+ std::unordered_map<int, int>::iterator def;
+ std::unordered_map<int, int>::const_iterator constI;
+
+ // Implicit conversion.
+ std::unordered_map<int, int>::const_iterator constI2 = def;
+ std::unordered_map<int, int>::const_iterator constI3(def);
+
+ // Explicit conversion
+ std::unordered_map<int, int>::const_iterator constI4
+ = std::unordered_map<int, int>::const_iterator(def);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto constI4
+ // CHECK-FIXES-NEXT: = std::unordered_map<int, int>::const_iterator(def);
+}
+
+void pointer_to_iterator() {
+ int_iterator I = Vec.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto I = Vec.begin();
+
+ // Pointers and references to iterators are not transformed.
+ int_iterator *IPtr = &I;
+ int_iterator &IRef = I;
+}
+
+void loop() {
+ for (std::vector<int>::iterator I = Vec.begin(); I != Vec.end(); ++I) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use auto when declaring iterators
+ // CHECK-FIXES: for (auto I = Vec.begin(); I != Vec.end(); ++I)
+ }
+
+ for (int_iterator I = Vec.begin(), E = Vec.end(); I != E; ++I) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use auto when declaring iterators
+ // CHECK-FIXES: for (auto I = Vec.begin(), E = Vec.end(); I != E; ++I)
+ }
+
+ std::vector<std::vector<int>::iterator> IterVec;
+ for (std::vector<int>::iterator I : IterVec) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use auto when declaring iterators
+ // CHECK-FIXES: for (auto I : IterVec)
+ }
+}
+
+void cv_qualifiers() {
+ // Make sure references and cv qualifiers don't get removed (i.e. replaced
+ // with just 'auto').
+ const auto & I = Vec.begin();
+ auto && I2 = Vec.begin();
+}
+
+void cleanup() {
+ // Passing a string as an argument to introduce a temporary object that will
+ // create an expression with cleanups.
+ std::map<std::string, int> MapFind;
+ std::map<std::string, int>::iterator I = MapFind.find("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto I = MapFind.find("foo");
+}
+
+void declaration_lists() {
+ // Declaration lists that match the declaration type with written no-list
+ // initializer are transformed.
+ std::vector<int>::iterator I = Vec.begin(), E = Vec.end();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto I = Vec.begin(), E = Vec.end();
+
+ // Declaration lists with non-initialized variables should not be transformed.
+ std::vector<int>::iterator J = Vec.begin(), K;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-min-type-name-length.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-min-type-name-length.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-min-type-name-length.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-min-type-name-length.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,85 @@
+// RUN: %check_clang_tidy -check-suffix=0-0 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- -frtti
+// RUN: %check_clang_tidy -check-suffix=0-8 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- -frtti
+// RUN: %check_clang_tidy -check-suffix=1-0 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- -frtti
+// RUN: %check_clang_tidy -check-suffix=1-8 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- -frtti
+
+template <class T> extern T foo();
+template <class T> struct P { explicit P(T t) : t_(t) {} T t_;};
+template <class T> P<T> *foo_ptr();
+template <class T> P<T> &foo_ref();
+
+int bar() {
+ {
+ // Lenth(long) = 4
+ long i = static_cast<long>(foo<long>());
+ // CHECK-FIXES-0-0: auto i = {{.*}}
+ // CHECK-FIXES-0-8: long i = {{.*}}
+ // CHECK-FIXES-1-0: auto i = {{.*}}
+ // CHECK-FIXES-1-8: long i = {{.*}}
+ const long ci = static_cast<long>(foo<const long>());
+ // CHECK-FIXES-0-0: auto ci = {{.*}}
+ // CHECK-FIXES-0-8: long ci = {{.*}}
+ // CHECK-FIXES-1-0: auto ci = {{.*}}
+ // CHECK-FIXES-1-8: long ci = {{.*}}
+ long *pi = static_cast<long *>(foo<long *>());
+ // CHECK-FIXES-0-0: auto *pi = {{.*}}
+ // CHECK-FIXES-0-8: long *pi = {{.*}}
+ // CHECK-FIXES-1-0: auto pi = {{.*}}
+ // CHECK-FIXES-1-8: long *pi = {{.*}}
+
+ // Length(long *) is still 5
+ long * pi2 = static_cast<long *>(foo<long *>());
+ // CHECK-FIXES-0-0: auto * pi2 = {{.*}}
+ // CHECK-FIXES-0-8: long * pi2 = {{.*}}
+ // CHECK-FIXES-1-0: auto pi2 = {{.*}}
+ // CHECK-FIXES-1-8: long * pi2 = {{.*}}
+
+ // Length(long **) = 6
+ long **ppi = static_cast<long **>(foo<long **>());
+ // CHECK-FIXES-0-0: auto **ppi = {{.*}}
+ // CHECK-FIXES-0-8: long **ppi = {{.*}}
+ // CHECK-FIXES-1-0: auto ppi = {{.*}}
+ // CHECK-FIXES-1-8: long **ppi = {{.*}}
+ }
+
+ {
+ // Lenth(long int) = 4 + 1 + 3 = 8
+ // Lenth(long int) is still 8
+ long int i = static_cast<long int>(foo<long int>());
+ // CHECK-FIXES-0-0: auto i = {{.*}}
+ // CHECK-FIXES-0-8: auto i = {{.*}}
+ // CHECK-FIXES-1-0: auto i = {{.*}}
+ // CHECK-FIXES-1-8: auto i = {{.*}}
+
+ long int *pi = static_cast<long int *>(foo<long int *>());
+ // CHECK-FIXES-0-0: auto *pi = {{.*}}
+ // CHECK-FIXES-0-8: auto *pi = {{.*}}
+ // CHECK-FIXES-1-0: auto pi = {{.*}}
+ // CHECK-FIXES-1-8: auto pi = {{.*}}
+ }
+
+ // Templates
+ {
+ // Length(P<long>) = 7
+ P<long>& i = static_cast<P<long>&>(foo_ref<long>());
+ // CHECK-FIXES-0-0: auto& i = {{.*}}
+ // CHECK-FIXES-0-8: P<long>& i = {{.*}}
+ // CHECK-FIXES-1-0: auto & i = {{.*}}
+ // CHECK-FIXES-1-8: P<long>& i = {{.*}}
+
+ // Length(P<long*>) = 8
+ P<long*>& pi = static_cast<P<long*> &>(foo_ref<long*>());
+ // CHECK-FIXES-0-0: auto& pi = {{.*}}
+ // CHECK-FIXES-0-8: auto& pi = {{.*}}
+ // CHECK-FIXES-1-0: auto & pi = {{.*}}
+ // CHECK-FIXES-1-8: auto & pi = {{.*}}
+
+ P<long>* pi2 = static_cast<P<long>*>(foo_ptr<long>());
+ // CHECK-FIXES-0-0: auto* pi2 = {{.*}}
+ // CHECK-FIXES-0-8: P<long>* pi2 = {{.*}}
+ // CHECK-FIXES-1-0: auto pi2 = {{.*}}
+ // CHECK-FIXES-1-8: auto pi2 = {{.*}}
+ }
+
+ return 1;
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new-remove-stars.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new-remove-stars.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new-remove-stars.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new-remove-stars.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,105 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: '1'}, {key: modernize-use-auto.MinTypeNameLength, value: '0'}]}"
+
+class MyType {};
+
+class MyDerivedType : public MyType {};
+
+// FIXME: the replacement sometimes results in two consecutive spaces after
+// the word 'auto' (due to the presence of spaces at both sides of '*').
+void auto_new() {
+ MyType *a_new = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a_new = new MyType();
+
+ static MyType *a_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto a_static = new MyType();
+
+ MyType *derived = new MyDerivedType();
+
+ void *vd = new MyType();
+
+ // CV-qualifier tests.
+ //
+ // NOTE : the form "type const" is expected here because of a deficiency in
+ // TypeLoc where CV qualifiers are not considered part of the type location
+ // info. That is, all that is being replaced in each case is "MyType *" and
+ // not "MyType * const".
+ static MyType * const d_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto const d_static = new MyType();
+
+ MyType * const a_const = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto const a_const = new MyType();
+
+ MyType * volatile vol = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto volatile vol = new MyType();
+
+ struct SType {} *stype = new SType;
+
+ int (**func)(int, int) = new (int(*[5])(int,int));
+
+ int *array = new int[5];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto array = new int[5];
+
+ MyType *ptr(new MyType);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto ptr(new MyType);
+
+ MyType *ptr2{new MyType};
+
+ {
+ // Test for declaration lists.
+ MyType *a = new MyType(), *b = new MyType(), *c = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a = new MyType(), b = new MyType(), c = new MyType();
+
+ // Non-initialized declaration should not be transformed.
+ MyType *d = new MyType(), *e;
+
+ MyType **f = new MyType*(), **g = new MyType*();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto f = new MyType*(), g = new MyType*();
+
+ // Mismatching types in declaration lists should not be transformed.
+ MyType *h = new MyType(), **i = new MyType*();
+
+ // '*' shouldn't be removed in case of mismatching types with multiple
+ // declarations.
+ MyType *j = new MyType(), *k = new MyType(), **l = new MyType*();
+ }
+
+ {
+ // Test for typedefs.
+ typedef int * int_p;
+ // CHECK-FIXES: typedef int * int_p;
+
+ int_p a = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a = new int;
+ int_p *b = new int*;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto b = new int*;
+
+ // Test for typedefs in declarations lists.
+ int_p c = new int, d = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto c = new int, d = new int;
+
+ // Different types should not be transformed.
+ int_p e = new int, *f = new int_p;
+
+ int_p *g = new int*, *h = new int_p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto g = new int*, h = new int_p;
+ }
+
+ // Don't warn when 'auto' is already being used.
+ auto aut = new MyType();
+ auto *paut = new MyType();
+ const auto *pcaut = new MyType();
+}
Added: clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new.cpp?rev=374540&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/checkers/modernize-use-auto-new.cpp Fri Oct 11 05:05:42 2019
@@ -0,0 +1,110 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '0'}]}" \
+// RUN: -- -frtti
+
+class MyType {};
+
+class MyDerivedType : public MyType {};
+
+// FIXME: the replacement sometimes results in two consecutive spaces after
+// the word 'auto' (due to the presence of spaces at both sides of '*').
+void auto_new() {
+ MyType *a_new = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *a_new = new MyType();
+
+ static MyType *a_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto *a_static = new MyType();
+
+ long long *ll = new long long();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *ll = new long long();
+
+ MyType *derived = new MyDerivedType();
+
+ void *vd = new MyType();
+
+ // CV-qualifier tests.
+ //
+ // NOTE : the form "type const" is expected here because of a deficiency in
+ // TypeLoc where CV qualifiers are not considered part of the type location
+ // info. That is, all that is being replaced in each case is "MyType *" and
+ // not "MyType * const".
+ static MyType * const d_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto * const d_static = new MyType();
+
+ MyType * const a_const = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto * const a_const = new MyType();
+
+ MyType * volatile vol = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto * volatile vol = new MyType();
+
+ struct SType {} *stype = new SType;
+
+ int (**func)(int, int) = new (int(*[5])(int,int));
+
+ int *array = new int[5];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *array = new int[5];
+
+ MyType *ptr(new MyType);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *ptr(new MyType);
+
+ MyType *ptr2{new MyType};
+
+ {
+ // Test for declaration lists.
+ MyType *a = new MyType(), *b = new MyType(), *c = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *a = new MyType(), *b = new MyType(), *c = new MyType();
+
+ // Non-initialized declaration should not be transformed.
+ MyType *d = new MyType(), *e;
+
+ MyType **f = new MyType*(), **g = new MyType*();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto **f = new MyType*(), **g = new MyType*();
+
+ // Mismatching types in declaration lists should not be transformed.
+ MyType *h = new MyType(), **i = new MyType*();
+
+ // '*' shouldn't be removed in case of mismatching types with multiple
+ // declarations.
+ MyType *j = new MyType(), *k = new MyType(), **l = new MyType*();
+ }
+
+ {
+ // Test for typedefs.
+ typedef int * int_p;
+ // CHECK-FIXES: typedef int * int_p;
+
+ int_p a = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a = new int;
+ int_p *b = new int*;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *b = new int*;
+
+ // Test for typedefs in declarations lists.
+ int_p c = new int, d = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto c = new int, d = new int;
+
+ // Different types should not be transformed.
+ int_p e = new int, *f = new int_p;
+
+ int_p *g = new int*, *h = new int_p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *g = new int*, *h = new int_p;
+ }
+
+ // Don't warn when 'auto' is already being used.
+ auto aut = new MyType();
+ auto *paut = new MyType();
+ const auto *pcaut = new MyType();
+}
More information about the cfe-commits
mailing list