1 | #include "ClangTidyOptions.h" |
2 | #include "ClangTidyTest.h" |
3 | #include "llvm/ADT/ArrayRef.h" |
4 | #include "llvm/ADT/StringRef.h" |
5 | #include "llvm/HeaderGuardCheck.h" |
6 | #include "llvm/IncludeOrderCheck.h" |
7 | #include "gtest/gtest.h" |
8 | #include <optional> |
9 | |
10 | using namespace clang::tidy::llvm_check; |
11 | |
12 | namespace clang { |
13 | namespace tidy { |
14 | namespace test { |
15 | |
16 | template <typename T> |
17 | static std::string runCheck(StringRef Code, const Twine &Filename, |
18 | std::optional<StringRef> ExpectedWarning, |
19 | std::map<StringRef, StringRef> PathsToContent = |
20 | std::map<StringRef, StringRef>()) { |
21 | std::vector<ClangTidyError> Errors; |
22 | std::string Result = test::runCheckOnCode<T>( |
23 | Code, &Errors, Filename, std::string("-xc++-header" ), ClangTidyOptions{}, |
24 | std::move(PathsToContent)); |
25 | if (Errors.size() != (size_t)ExpectedWarning.has_value()) |
26 | return "invalid error count" ; |
27 | if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message) |
28 | return "expected: '" + ExpectedWarning->str() + "', saw: '" + |
29 | Errors.back().Message.Message + "'" ; |
30 | return Result; |
31 | } |
32 | |
33 | static std::string |
34 | (StringRef Code, const Twine &Filename, |
35 | std::optional<StringRef> ExpectedWarning) { |
36 | return runCheck<LLVMHeaderGuardCheck>(Code, Filename, |
37 | ExpectedWarning: std::move(ExpectedWarning)); |
38 | } |
39 | |
40 | static std::string |
41 | runIncludeOrderCheck(StringRef Code, const Twine &Filename, |
42 | std::optional<StringRef> ExpectedWarning, |
43 | llvm::ArrayRef<llvm::StringLiteral> Includes) { |
44 | std::map<StringRef, StringRef> PathsToContent; |
45 | for (auto Include : Includes) |
46 | PathsToContent.emplace(args&: Include, args: "" ); |
47 | return runCheck<IncludeOrderCheck>(Code, Filename, ExpectedWarning: std::move(ExpectedWarning), |
48 | PathsToContent); |
49 | } |
50 | |
51 | namespace { |
52 | struct : public LLVMHeaderGuardCheck { |
53 | (StringRef Name, ClangTidyContext *Context) |
54 | : LLVMHeaderGuardCheck(Name, Context) {} |
55 | bool (StringRef Filename) override { return true; } |
56 | }; |
57 | |
58 | static std::string |
59 | (StringRef Code, const Twine &Filename, |
60 | std::optional<StringRef> ExpectedWarning) { |
61 | return runCheck<WithEndifComment>(Code, Filename, ExpectedWarning: std::move(ExpectedWarning)); |
62 | } |
63 | } // namespace |
64 | |
65 | TEST(LLVMHeaderGuardCheckTest, FixHeaderGuards) { |
66 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
67 | "#define LLVM_ADT_FOO_H\n" |
68 | "#endif\n" , |
69 | runHeaderGuardCheck( |
70 | "#ifndef FOO\n" |
71 | "#define FOO\n" |
72 | "#endif\n" , |
73 | "include/llvm/ADT/foo.h" , |
74 | StringRef("header guard does not follow preferred style" ))); |
75 | |
76 | // Allow trailing underscores. |
77 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n" |
78 | "#define LLVM_ADT_FOO_H_\n" |
79 | "#endif\n" , |
80 | runHeaderGuardCheck("#ifndef LLVM_ADT_FOO_H_\n" |
81 | "#define LLVM_ADT_FOO_H_\n" |
82 | "#endif\n" , |
83 | "include/llvm/ADT/foo.h" , std::nullopt)); |
84 | |
85 | EXPECT_EQ("#ifndef LLVM_CLANG_C_BAR_H\n" |
86 | "#define LLVM_CLANG_C_BAR_H\n" |
87 | "\n" |
88 | "\n" |
89 | "#endif\n" , |
90 | runHeaderGuardCheck("" , "./include/clang-c/bar.h" , |
91 | StringRef("header is missing header guard" ))); |
92 | |
93 | EXPECT_EQ("#ifndef LLVM_CLANG_LIB_CODEGEN_C_H\n" |
94 | "#define LLVM_CLANG_LIB_CODEGEN_C_H\n" |
95 | "\n" |
96 | "\n" |
97 | "#endif\n" , |
98 | runHeaderGuardCheck("" , "tools/clang/lib/CodeGen/c.h" , |
99 | StringRef("header is missing header guard" ))); |
100 | |
101 | EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n" |
102 | "#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n" |
103 | "\n" |
104 | "\n" |
105 | "#endif\n" , |
106 | runHeaderGuardCheck("" , "tools/clang/tools/extra/clang-tidy/x.h" , |
107 | StringRef("header is missing header guard" ))); |
108 | |
109 | EXPECT_EQ( |
110 | "int foo;\n" |
111 | "#ifndef LLVM_CLANG_BAR_H\n" |
112 | "#define LLVM_CLANG_BAR_H\n" |
113 | "#endif\n" , |
114 | runHeaderGuardCheck("int foo;\n" |
115 | "#ifndef LLVM_CLANG_BAR_H\n" |
116 | "#define LLVM_CLANG_BAR_H\n" |
117 | "#endif\n" , |
118 | "include/clang/bar.h" , |
119 | StringRef("code/includes outside of area guarded by " |
120 | "header guard; consider moving it" ))); |
121 | |
122 | EXPECT_EQ( |
123 | "#ifndef LLVM_CLANG_BAR_H\n" |
124 | "#define LLVM_CLANG_BAR_H\n" |
125 | "#endif\n" |
126 | "int foo;\n" , |
127 | runHeaderGuardCheck("#ifndef LLVM_CLANG_BAR_H\n" |
128 | "#define LLVM_CLANG_BAR_H\n" |
129 | "#endif\n" |
130 | "int foo;\n" , |
131 | "include/clang/bar.h" , |
132 | StringRef("code/includes outside of area guarded by " |
133 | "header guard; consider moving it" ))); |
134 | |
135 | EXPECT_EQ("#ifndef LLVM_CLANG_BAR_H\n" |
136 | "#define LLVM_CLANG_BAR_H\n" |
137 | "\n" |
138 | "int foo;\n" |
139 | "#ifndef FOOLOLO\n" |
140 | "#define FOOLOLO\n" |
141 | "#endif\n" |
142 | "\n" |
143 | "#endif\n" , |
144 | runHeaderGuardCheck("int foo;\n" |
145 | "#ifndef FOOLOLO\n" |
146 | "#define FOOLOLO\n" |
147 | "#endif\n" , |
148 | "include/clang/bar.h" , |
149 | StringRef("header is missing header guard" ))); |
150 | |
151 | // Fix incorrect #endif comments even if we shouldn't add new ones. |
152 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
153 | "#define LLVM_ADT_FOO_H\n" |
154 | "#endif // LLVM_ADT_FOO_H\n" , |
155 | runHeaderGuardCheck( |
156 | "#ifndef FOO\n" |
157 | "#define FOO\n" |
158 | "#endif // FOO\n" , |
159 | "include/llvm/ADT/foo.h" , |
160 | StringRef("header guard does not follow preferred style" ))); |
161 | |
162 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
163 | "#define LLVM_ADT_FOO_H\n" |
164 | "#endif // LLVM_ADT_FOO_H\n" , |
165 | runHeaderGuardCheckWithEndif( |
166 | "#ifndef FOO\n" |
167 | "#define FOO\n" |
168 | "#endif\n" , |
169 | "include/llvm/ADT/foo.h" , |
170 | StringRef("header guard does not follow preferred style" ))); |
171 | |
172 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
173 | "#define LLVM_ADT_FOO_H\n" |
174 | "#endif // LLVM_ADT_FOO_H\n" , |
175 | runHeaderGuardCheckWithEndif( |
176 | "#ifndef LLVM_ADT_FOO_H\n" |
177 | "#define LLVM_ADT_FOO_H\n" |
178 | "#endif // LLVM_H\n" , |
179 | "include/llvm/ADT/foo.h" , |
180 | StringRef("#endif for a header guard should reference the " |
181 | "guard macro in a comment" ))); |
182 | |
183 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
184 | "#define LLVM_ADT_FOO_H\n" |
185 | "#endif /* LLVM_ADT_FOO_H */\n" , |
186 | runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n" |
187 | "#define LLVM_ADT_FOO_H\n" |
188 | "#endif /* LLVM_ADT_FOO_H */\n" , |
189 | "include/llvm/ADT/foo.h" , |
190 | std::nullopt)); |
191 | |
192 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n" |
193 | "#define LLVM_ADT_FOO_H_\n" |
194 | "#endif // LLVM_ADT_FOO_H_\n" , |
195 | runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H_\n" |
196 | "#define LLVM_ADT_FOO_H_\n" |
197 | "#endif // LLVM_ADT_FOO_H_\n" , |
198 | "include/llvm/ADT/foo.h" , |
199 | std::nullopt)); |
200 | |
201 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
202 | "#define LLVM_ADT_FOO_H\n" |
203 | "#endif // LLVM_ADT_FOO_H\n" , |
204 | runHeaderGuardCheckWithEndif( |
205 | "#ifndef LLVM_ADT_FOO_H_\n" |
206 | "#define LLVM_ADT_FOO_H_\n" |
207 | "#endif // LLVM\n" , |
208 | "include/llvm/ADT/foo.h" , |
209 | StringRef("header guard does not follow preferred style" ))); |
210 | |
211 | // An extra space inside the comment is OK. |
212 | llvm::StringRef = "#ifndef LLVM_ADT_FOO_H\n" |
213 | "#define LLVM_ADT_FOO_H\n" |
214 | "#endif // LLVM_ADT_FOO_H\n" ; |
215 | EXPECT_EQ(WithExtraSpace, |
216 | runHeaderGuardCheckWithEndif( |
217 | WithExtraSpace, "include/llvm/ADT/foo.h" , std::nullopt)); |
218 | |
219 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
220 | "#define LLVM_ADT_FOO_H\n" |
221 | "#endif \\ \n" |
222 | "// LLVM_ADT_FOO_H\n" , |
223 | runHeaderGuardCheckWithEndif( |
224 | "#ifndef LLVM_ADT_FOO_H\n" |
225 | "#define LLVM_ADT_FOO_H\n" |
226 | "#endif \\ \n" |
227 | "// LLVM_ADT_FOO_H\n" , |
228 | "include/llvm/ADT/foo.h" , |
229 | StringRef("backslash and newline separated by space" ))); |
230 | |
231 | EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
232 | "#define LLVM_ADT_FOO_H\n" |
233 | "#endif /* LLVM_ADT_FOO_H\\ \n" |
234 | " FOO */" , |
235 | runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n" |
236 | "#define LLVM_ADT_FOO_H\n" |
237 | "#endif /* LLVM_ADT_FOO_H\\ \n" |
238 | " FOO */" , |
239 | "include/llvm/ADT/foo.h" , |
240 | std::nullopt)); |
241 | |
242 | EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
243 | "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
244 | "\n" |
245 | "\n" |
246 | "#endif\n" , |
247 | runHeaderGuardCheck( |
248 | "" , "/llvm-project/clang-tools-extra/clangd/foo.h" , |
249 | StringRef("header is missing header guard" ))); |
250 | |
251 | // Substitution of characters should not result in a header guard starting |
252 | // with "_". |
253 | EXPECT_EQ("#ifndef BAR_H\n" |
254 | "#define BAR_H\n" |
255 | "\n" |
256 | "\n" |
257 | "#endif\n" , |
258 | runHeaderGuardCheck("" , "include/--bar.h" , |
259 | StringRef("header is missing header guard" ))); |
260 | |
261 | #ifdef WIN32 |
262 | // Check interaction with Windows-style path separators (\). |
263 | EXPECT_EQ( |
264 | "#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
265 | "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
266 | "\n" |
267 | "\n" |
268 | "#endif\n" , |
269 | runHeaderGuardCheck("" , "llvm-project\\clang-tools-extra\\clangd\\foo.h" , |
270 | StringRef("header is missing header guard" ))); |
271 | |
272 | EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
273 | "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
274 | "\n" |
275 | "\n" |
276 | "#endif\n" , |
277 | runHeaderGuardCheck( |
278 | "" , "C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h" , |
279 | StringRef("header is missing header guard" ))); |
280 | |
281 | EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
282 | "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
283 | "\n" |
284 | "\n" |
285 | "#endif\n" , |
286 | runHeaderGuardCheck( |
287 | "" , |
288 | "\\\\SMBShare\\llvm-project\\clang-tools-extra\\clangd\\foo.h" , |
289 | StringRef("header is missing header guard" ))); |
290 | |
291 | EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
292 | "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
293 | "\n" |
294 | "\n" |
295 | "#endif\n" , |
296 | runHeaderGuardCheck( |
297 | "" , "\\\\?\\C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h" , |
298 | StringRef("header is missing header guard" ))); |
299 | #endif |
300 | } |
301 | |
302 | TEST(IncludeOrderCheck, GTestHeaders) { |
303 | EXPECT_EQ( |
304 | R"cpp( |
305 | #include "foo.h" |
306 | #include "llvm/foo.h" |
307 | #include "gtest/foo.h" |
308 | #include <algorithm>)cpp" , |
309 | runIncludeOrderCheck( |
310 | R"cpp( |
311 | #include "foo.h" |
312 | #include "llvm/foo.h" |
313 | #include <algorithm> |
314 | #include "gtest/foo.h")cpp" , |
315 | "foo.cc" , StringRef("#includes are not sorted properly" ), |
316 | {"foo.h" , "algorithm" , "gtest/foo.h" , "llvm/foo.h" })); |
317 | } |
318 | |
319 | } // namespace test |
320 | } // namespace tidy |
321 | } // namespace clang |
322 | |