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
10using namespace clang::tidy::llvm_check;
11
12namespace clang {
13namespace tidy {
14namespace test {
15
16template <typename T>
17static 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
33static std::string
34runHeaderGuardCheck(StringRef Code, const Twine &Filename,
35 std::optional<StringRef> ExpectedWarning) {
36 return runCheck<LLVMHeaderGuardCheck>(Code, Filename,
37 ExpectedWarning: std::move(ExpectedWarning));
38}
39
40static std::string
41runIncludeOrderCheck(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
51namespace {
52struct WithEndifComment : public LLVMHeaderGuardCheck {
53 WithEndifComment(StringRef Name, ClangTidyContext *Context)
54 : LLVMHeaderGuardCheck(Name, Context) {}
55 bool shouldSuggestEndifComment(StringRef Filename) override { return true; }
56};
57
58static std::string
59runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename,
60 std::optional<StringRef> ExpectedWarning) {
61 return runCheck<WithEndifComment>(Code, Filename, ExpectedWarning: std::move(ExpectedWarning));
62}
63} // namespace
64
65TEST(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 WithExtraSpace = "#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
302TEST(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

source code of clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp