xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/cert/dcl58-cpp.cpp (revision ab9ee471dfda27b3cfb4a350e406576512ce9053)
1 // RUN: %check_clang_tidy -std=c++17-or-later %s cert-dcl58-cpp %t -- -- -I %clang_tidy_headers
2 
3 #include "system-header-simulation.h"
4 
5 namespace A {
6   namespace B {
7     int b;
8   }
9 }
10 
11 namespace A {
12   namespace B {
13     int c;
14   }
15 }
16 
17 namespace posix {
18 // CHECK-MESSAGES: :[[@LINE+2]]:11: warning: modification of 'posix' namespace can result in undefined behavior [cert-dcl58-cpp]
19 // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here
20 namespace foo {
21 int foobar;
22 }
23 }
24 
25 namespace std {
26 // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: modification of 'std' namespace
27 // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here
28 int stdInt;
29 // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: modification of 'std' namespace
30 // CHECK-MESSAGES: :[[@LINE-5]]:11: note: 'std' namespace opened here
31 int stdInt1;
32 }
33 
34 namespace foobar {
35   namespace std {
36     int bar;
37   }
38 }
39 
40 namespace posix {
41 // CHECK-MESSAGES: :[[@LINE+2]]:11: warning: modification of 'posix' namespace
42 // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here
43 namespace std {
44 }
45 } // namespace posix
46 
47 namespace posix::a {
48 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: modification of 'posix' namespace
49 // CHECK-MESSAGES: :[[@LINE-2]]:11: note: 'posix' namespace opened here
50 }
51 
52 namespace std {
53 // no-warning: empty
54 } // namespace std
55 
56 namespace std {
57 // Warn for non-NamedDecls as well.
58 // CHECK-MESSAGES: :[[@LINE+2]]:1: warning: modification of 'std' namespace
59 // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
60 static_assert(1 == 1, "non-NamedDecl");
61 } // namespace std
62 
63 enum class MyError {
64   ErrorA,
65   ErrorB
66 };
67 
68 namespace std {
69 // no-warning: Class template specialized by a program-defined type.
70 template <>
71 struct is_error_code_enum<MyError> : std::true_type {};
72 
73 // no-warning: Function template specialized by a program-defined type.
74 template<>
75 void swap<MyError>(MyError &a, MyError &b);
76 }
77 
78 using ConstBoolPtr = const bool *;
79 
80 namespace std {
81 // class template, builtin type
82 // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
83 // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
84 template <>
85 struct is_error_code_enum<bool> : std::true_type {};
86 // function template, builtin type
87 // CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace
88 // CHECK-MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here
89 template <>
90 void swap<bool>(bool &, bool &);
91 // CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace
92 // CHECK-MESSAGES: :[[@LINE-12]]:11: note: 'std' namespace opened here
93 template <>
94 void swap<ConstBoolPtr>(ConstBoolPtr &, ConstBoolPtr &);
95 } // namespace std
96 
97 namespace std {
98 // class template, std type
99 // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
100 // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
101 template <>
102 struct is_error_code_enum<std::io_errc> : std::true_type {};
103 // function template, std type
104 // CHECK-MESSAGES: :[[@LINE+3]]:6: warning: modification of 'std' namespace
105 // CHECK-MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here
106 template <>
107 void swap<std::io_errc>(std::io_errc &, std::io_errc &);
108 } // namespace std
109 
110 // parameter pack, has program-defined type
111 namespace std {
112 // no-warning: there is one program-defined type.
113 template <>
114 class tuple<int, MyError, std::io_errc> {};
115 } // namespace std
116 
117 // parameter pack, only builtin or std type
118 namespace std {
119 // Forbid variadic specializations over only `std::` or builtin types.
120 // CHECK-MESSAGES: :[[@LINE+3]]:7: warning: modification of 'std' namespace
121 // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
122 template <>
123 class tuple<int, const std::io_errc, float> {};
124 } // namespace std
125 
126 namespace std {
127 // Test nested standard declarations.
128 // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
129 // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
130 template <>
131 struct is_error_code_enum<std::Outer::Inner> : std::true_type {};
132 } // namespace std
133 
134 namespace std {
135 // Test nested namespace.
136 // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
137 // CHECK-MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
138 template <>
139 struct is_error_code_enum<std::detail::X> : std::true_type {};
140 } // namespace std
141 
142 // Test member function template specializations.
143 namespace std {
144 // CHECK-MESSAGES: :[[@LINE+3]]:18: warning: modification of 'std' namespace
145 // CHECK_MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here
146 template <>
operator()147 bool less<void>::operator()<int &&, float &&>(int &&, float &&) const {
148   return true;
149 }
150 // CHECK-MESSAGES: :[[@LINE+3]]:18: warning: modification of 'std' namespace
151 // CHECK_MESSAGES: :[[@LINE-8]]:11: note: 'std' namespace opened here
152 template <>
operator()153 bool less<void>::operator()<MyError &&, MyError &&>(MyError &&, MyError &&) const {
154   return true;
155 }
156 } // namespace std
157 
158 // Test member class template specializations.
159 namespace std {
160 // CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace
161 // CHECK_MESSAGES: :[[@LINE-2]]:11: note: 'std' namespace opened here
162 template <>
163 struct less<void>::X<bool> {};
164 // CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace
165 // CHECK_MESSAGES: :[[@LINE-6]]:11: note: 'std' namespace opened here
166 template <>
167 struct less<void>::X<MyError> {};
168 // CHECK-MESSAGES: :[[@LINE+3]]:20: warning: modification of 'std' namespace
169 // CHECK_MESSAGES: :[[@LINE-10]]:11: note: 'std' namespace opened here
170 template <typename T>
171 struct less<void>::X<MyError, T> {};
172 } // namespace std
173 
174 // We did not open the 'std' namespace, but still specialized the member
175 // function of 'std::less'.
176 // CHECK-MESSAGES: :[[@LINE+3]]:23: warning: modification of 'std' namespace
177 // no-note: There is no opening of 'std' namespace, hence no note emitted.
178 template <>
operator()179 bool std::less<void>::operator()<int &&, int &&>(int &&, int &&) const {
180   return true;
181 }
182 
183 namespace SpaceA {
184 namespace SpaceB {
185 class MapKey {
186   int Type = 0;
187 
188 public:
189   MapKey() = default;
getType() const190   int getType() const { return Type; }
191 };
192 } // namespace SpaceB
193 } // namespace SpaceA
194 
195 // no-warning: Specializing for 'std::hash' for a program-defined type.
196 template <>
197 struct std::hash<::SpaceA::SpaceB::MapKey> {
198   // no-warning
operator ()std::hash199   unsigned long operator()(const ::SpaceA::SpaceB::MapKey &K) const {
200     return K.getType();
201   }
202   // no-warning
operator ()std::hash203   bool operator()(const ::SpaceA::SpaceB::MapKey &K1,
204                   const ::SpaceA::SpaceB::MapKey &K2) const {
205     return K1.getType() < K2.getType();
206   }
207 };
208 
209 using myint = int;
210 
211 // The type alias declaration is the same as typedef, does not introduce a
212 // program-defined type.
213 // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: modification of 'std' namespace
214 template <>
215 struct std::hash<myint> {
216   // no-warning: The warning was already reported for the struct itself.
operator ()std::hash217   unsigned long operator()(const myint &K) const {
218     return K;
219   }
220   // no-warning: The warning was already reported for the struct itself.
operator ()std::hash221   bool operator()(const myint &K1,
222                   const myint &K2) const {
223     return K1 < K2;
224   }
225 };
226 
227 // CHECK-MESSAGES: :[[@LINE+2]]:15: warning: modification of 'std' namespace
228 template <>
229 struct ::std::hash<long> {
operator ()std::hash230   unsigned long operator()(const long &K) const {
231     return K;
232   }
233 };
234 
235 namespace ranges {
236 namespace detail {
237 struct diffmax_t {};
238 using LongT = long;
239 } // namespace detail
240 } // namespace ranges
241 
242 namespace std {
243 // no-warning: specialization with an user-defined type
244 template <>
245 struct numeric_limits<::ranges::detail::diffmax_t> {
246   static constexpr bool is_signed = true;
247   static constexpr bool is_integer = true;
maxstd::numeric_limits248   static constexpr ::ranges::detail::diffmax_t max() noexcept {
249     return {};
250   }
251 };
252 inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_signed;
253 inline constexpr bool numeric_limits<::ranges::detail::diffmax_t>::is_integer;
254 } // namespace std
255 
256 namespace std {
257 // specialization with type alias to non-program-defined-type
258 // CHECK-MESSAGES: :[[@LINE+3]]:8: warning: modification of 'std' namespace
259 // CHECK_MESSAGES: :[[@LINE-3]]:11: note: 'std' namespace opened here
260 template <>
261 struct numeric_limits<::ranges::detail::LongT> {
262   static constexpr bool is_signed = true;
263   static constexpr bool is_integer = true;
maxstd::numeric_limits264   static constexpr ::ranges::detail::LongT max() noexcept {
265     return 1;
266   }
267 };
268 inline constexpr bool numeric_limits<::ranges::detail::LongT>::is_signed;
269 inline constexpr bool numeric_limits<::ranges::detail::LongT>::is_integer;
270 } // namespace std
271 
272 namespace no_crash {
273 struct A
274 {
275   friend struct B;
276 };
277 
278 struct B;
279 
280 template<typename> struct T {};
281 
282 T<B> b;
283 }
284