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