aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification.cpp')
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification.cpp
new file mode 100644
index 0000000..32bcbca
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/std-namespace-modification.cpp
@@ -0,0 +1,283 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-std-namespace-modification %t -- -- -I %clang_tidy_headers
+
+#include "system-header-simulation.h"
+
+namespace A {
+ namespace B {
+ int b;
+ }
+}
+
+namespace A {
+ namespace B {
+ int c;
+ }
+}
+
+namespace posix {
+// CHECK-MESSAGES: :[[@LINE+2]]:11: warning: modification of 'posix' namespace can result in undefined behavior [bugprone-std-namespace-modification]
+// CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here
+namespace foo {
+int foobar;
+}
+}
+
+namespace std {
+// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here
+int stdInt;
+// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-5]]:11: note: 'std' namespace opened here
+int stdInt1;
+}
+
+namespace foobar {
+ namespace std {
+ int bar;
+ }
+}
+
+namespace posix {
+// CHECK-MESSAGES: :[[@LINE+2]]:11: warning: modification of 'posix' namespace
+// CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here
+namespace std {
+}
+} // namespace posix
+
+namespace posix::a {
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: modification of 'posix' namespace
+// CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here
+}
+
+namespace std {
+// no-warning: empty
+} // namespace std
+
+namespace std {
+// Warn for non-NamedDecls as well.
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
+static_assert(1 == 1, "non-NamedDecl");
+} // namespace std
+
+enum class MyError {
+ ErrorA,
+ ErrorB
+};
+
+namespace std {
+// no-warning: Class template specialized by a program-defined type.
+template <>
+struct is_error_code_enum<MyError> : std::true_type {};
+
+// no-warning: Function template specialized by a program-defined type.
+template<>
+void swap<MyError>(MyError &a, MyError &b);
+}
+
+using ConstBoolPtr = const bool *;
+
+namespace std {
+// class template, builtin type
+// CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
+template <>
+struct is_error_code_enum<bool> : std::true_type {};
+// function template, builtin type
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here
+template <>
+void swap<bool>(bool &, bool &);
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-12]]:11: note: 'std' namespace opened here
+template <>
+void swap<ConstBoolPtr>(ConstBoolPtr &, ConstBoolPtr &);
+} // namespace std
+
+namespace std {
+// class template, std type
+// CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
+template <>
+struct is_error_code_enum<std::io_errc> : std::true_type {};
+// function template, std type
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here
+template <>
+void swap<std::io_errc>(std::io_errc &, std::io_errc &);
+} // namespace std
+
+// parameter pack, has program-defined type
+namespace std {
+// no-warning: there is one program-defined type.
+template <>
+class tuple<int, MyError, std::io_errc> {};
+} // namespace std
+
+// parameter pack, only builtin or std type
+namespace std {
+// Forbid variadic specializations over only `std::` or builtin types.
+// CHECK-MESSAGES: :[[@LINE+3]]:7: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
+template <>
+class tuple<int, const std::io_errc, float> {};
+} // namespace std
+
+namespace std {
+// Test nested standard declarations.
+// CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
+template <>
+struct is_error_code_enum<std::Outer::Inner> : std::true_type {};
+} // namespace std
+
+namespace std {
+// Test nested namespace.
+// CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
+// CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
+template <>
+struct is_error_code_enum<std::detail::X> : std::true_type {};
+} // namespace std
+
+// Test member function template specializations.
+namespace std {
+// CHECK-MESSAGES: :[[@LINE+3]]:18: warning: modification of 'std' namespace
+// CHECK_MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here
+template <>
+bool less<void>::operator()<int &&, float &&>(int &&, float &&) const {
+ return true;
+}
+// CHECK-MESSAGES: :[[@LINE+3]]:18: warning: modification of 'std' namespace
+// CHECK_MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here
+template <>
+bool less<void>::operator()<MyError &&, MyError &&>(MyError &&, MyError &&) const {
+ return true;
+}
+} // namespace std
+
+// Test member class template specializations.
+namespace std {
+// CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace
+// CHECK_MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here
+template <>
+struct less<void>::X<bool> {};
+// CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace
+// CHECK_MESSAGES: :[[@LINE-6]]:11: note: 'std' namespace opened here
+template <>
+struct less<void>::X<MyError> {};
+// CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace
+// CHECK_MESSAGES: :[[@LINE-10]]:11: note: 'std' namespace opened here
+template <typename T>
+struct less<void>::X<MyError, T> {};
+} // namespace std
+
+// We did not open the 'std' namespace, but still specialized the member
+// function of 'std::less'.
+// CHECK-MESSAGES: :[[@LINE+3]]:23: warning: modification of 'std' namespace
+// no-note: There is no opening of 'std' namespace, hence no note emitted.
+template <>
+bool std::less<void>::operator()<int &&, int &&>(int &&, int &&) const {
+ return true;
+}
+
+namespace SpaceA {
+namespace SpaceB {
+class MapKey {
+ int Type = 0;
+
+public:
+ MapKey() = default;
+ int getType() const { return Type; }
+};
+} // namespace SpaceB
+} // namespace SpaceA
+
+// no-warning: Specializing for 'std::hash' for a program-defined type.
+template <>
+struct std::hash<::SpaceA::SpaceB::MapKey> {
+ // no-warning
+ unsigned long operator()(const ::SpaceA::SpaceB::MapKey &K) const {
+ return K.getType();
+ }
+ // no-warning
+ bool operator()(const ::SpaceA::SpaceB::MapKey &K1,
+ const ::SpaceA::SpaceB::MapKey &K2) const {
+ return K1.getType() < K2.getType();
+ }
+};
+
+using myint = int;
+
+// The type alias declaration is the same as typedef, does not introduce a
+// program-defined type.
+// CHECK-MESSAGES: :[[@LINE+2]]:13: warning: modification of 'std' namespace
+template <>
+struct std::hash<myint> {
+ // no-warning: The warning was already reported for the struct itself.
+ unsigned long operator()(const myint &K) const {
+ return K;
+ }
+ // no-warning: The warning was already reported for the struct itself.
+ bool operator()(const myint &K1,
+ const myint &K2) const {
+ return K1 < K2;
+ }
+};
+
+// CHECK-MESSAGES: :[[@LINE+2]]:15: warning: modification of 'std' namespace
+template <>
+struct ::std::hash<long> {
+ unsigned long operator()(const long &K) const {
+ return K;
+ }
+};
+
+namespace ranges {
+namespace detail {
+struct diffmax_t {};
+using LongT = long;
+} // namespace detail
+} // namespace ranges
+
+namespace std {
+// no-warning: specialization with an user-defined type
+template <>
+struct numeric_limits<::ranges::detail::diffmax_t> {
+ static constexpr bool is_signed = true;
+ static constexpr bool is_integer = true;
+ static constexpr ::ranges::detail::diffmax_t max() noexcept {
+ return {};
+ }
+};
+inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_signed;
+inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_integer;
+} // namespace std
+
+namespace std {
+// specialization with type alias to non-program-defined-type
+// CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
+// CHECK_MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
+template <>
+struct numeric_limits<::ranges::detail::LongT> {
+ static constexpr bool is_signed = true;
+ static constexpr bool is_integer = true;
+ static constexpr ::ranges::detail::LongT max() noexcept {
+ return 1;
+ }
+};
+inline constexpr bool numeric_limits<::ranges::detail::LongT>::is_signed;
+inline constexpr bool numeric_limits<::ranges::detail::LongT>::is_integer;
+} // namespace std
+
+namespace no_crash {
+struct A
+{
+ friend struct B;
+};
+
+struct B;
+
+template<typename> struct T {};
+
+T<B> b;
+}