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"
10 using namespace clang::tidy::llvm_check
;
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
+ "'";
34 runHeaderGuardCheck(StringRef Code
, const Twine
&Filename
,
35 std::optional
<StringRef
> ExpectedWarning
) {
36 return runCheck
<LLVMHeaderGuardCheck
>(Code
, Filename
,
37 std::move(ExpectedWarning
));
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(Include
, "");
47 return runCheck
<IncludeOrderCheck
>(Code
, Filename
, std::move(ExpectedWarning
),
52 struct WithEndifComment
: public LLVMHeaderGuardCheck
{
53 WithEndifComment(StringRef Name
, ClangTidyContext
*Context
)
54 : LLVMHeaderGuardCheck(Name
, Context
) {}
55 bool shouldSuggestEndifComment(StringRef Filename
) override
{ return true; }
59 runHeaderGuardCheckWithEndif(StringRef Code
, const Twine
&Filename
,
60 std::optional
<StringRef
> ExpectedWarning
) {
61 return runCheck
<WithEndifComment
>(Code
, Filename
, std::move(ExpectedWarning
));
65 TEST(LLVMHeaderGuardCheckTest
, FixHeaderGuards
) {
66 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
67 "#define LLVM_ADT_FOO_H\n"
73 "include/llvm/ADT/foo.h",
74 StringRef("header guard does not follow preferred style")));
76 // Allow trailing underscores.
77 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n"
78 "#define LLVM_ADT_FOO_H_\n"
80 runHeaderGuardCheck("#ifndef LLVM_ADT_FOO_H_\n"
81 "#define LLVM_ADT_FOO_H_\n"
83 "include/llvm/ADT/foo.h", std::nullopt
));
85 EXPECT_EQ("#ifndef LLVM_CLANG_C_BAR_H\n"
86 "#define LLVM_CLANG_C_BAR_H\n"
90 runHeaderGuardCheck("", "./include/clang-c/bar.h",
91 StringRef("header is missing header guard")));
93 EXPECT_EQ("#ifndef LLVM_CLANG_LIB_CODEGEN_C_H\n"
94 "#define LLVM_CLANG_LIB_CODEGEN_C_H\n"
98 runHeaderGuardCheck("", "tools/clang/lib/CodeGen/c.h",
99 StringRef("header is missing header guard")));
101 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n"
102 "#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n"
106 runHeaderGuardCheck("", "tools/clang/tools/extra/clang-tidy/x.h",
107 StringRef("header is missing header guard")));
111 "#ifndef LLVM_CLANG_BAR_H\n"
112 "#define LLVM_CLANG_BAR_H\n"
114 runHeaderGuardCheck("int foo;\n"
115 "#ifndef LLVM_CLANG_BAR_H\n"
116 "#define LLVM_CLANG_BAR_H\n"
118 "include/clang/bar.h",
119 StringRef("code/includes outside of area guarded by "
120 "header guard; consider moving it")));
123 "#ifndef LLVM_CLANG_BAR_H\n"
124 "#define LLVM_CLANG_BAR_H\n"
127 runHeaderGuardCheck("#ifndef LLVM_CLANG_BAR_H\n"
128 "#define LLVM_CLANG_BAR_H\n"
131 "include/clang/bar.h",
132 StringRef("code/includes outside of area guarded by "
133 "header guard; consider moving it")));
135 EXPECT_EQ("#ifndef LLVM_CLANG_BAR_H\n"
136 "#define LLVM_CLANG_BAR_H\n"
144 runHeaderGuardCheck("int foo;\n"
148 "include/clang/bar.h",
149 StringRef("header is missing header guard")));
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",
159 "include/llvm/ADT/foo.h",
160 StringRef("header guard does not follow preferred style")));
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(
169 "include/llvm/ADT/foo.h",
170 StringRef("header guard does not follow preferred style")));
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")));
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",
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",
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"
208 "include/llvm/ADT/foo.h",
209 StringRef("header guard does not follow preferred style")));
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
));
219 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
220 "#define LLVM_ADT_FOO_H\n"
222 "// LLVM_ADT_FOO_H\n",
223 runHeaderGuardCheckWithEndif(
224 "#ifndef LLVM_ADT_FOO_H\n"
225 "#define LLVM_ADT_FOO_H\n"
227 "// LLVM_ADT_FOO_H\n",
228 "include/llvm/ADT/foo.h",
229 StringRef("backslash and newline separated by space")));
231 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
232 "#define LLVM_ADT_FOO_H\n"
233 "#endif /* LLVM_ADT_FOO_H\\ \n"
235 runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n"
236 "#define LLVM_ADT_FOO_H\n"
237 "#endif /* LLVM_ADT_FOO_H\\ \n"
239 "include/llvm/ADT/foo.h",
242 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
243 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
248 "", "/llvm-project/clang-tools-extra/clangd/foo.h",
249 StringRef("header is missing header guard")));
251 // Substitution of characters should not result in a header guard starting
253 EXPECT_EQ("#ifndef BAR_H\n"
258 runHeaderGuardCheck("", "include/--bar.h",
259 StringRef("header is missing header guard")));
262 // Check interaction with Windows-style path separators (\).
264 "#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
265 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
269 runHeaderGuardCheck("", "llvm-project\\clang-tools-extra\\clangd\\foo.h",
270 StringRef("header is missing header guard")));
272 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
273 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
278 "", "C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
279 StringRef("header is missing header guard")));
281 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
282 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
288 "\\\\SMBShare\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
289 StringRef("header is missing header guard")));
291 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
292 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
297 "", "\\\\?\\C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
298 StringRef("header is missing header guard")));
302 TEST(IncludeOrderCheck
, GTestHeaders
) {
306 #include "llvm
/foo
.h
"
307 #include "gtest
/foo
.h
"
308 #include <algorithm>)cpp",
309 runIncludeOrderCheck(
312 #include "llvm
/foo
.h
"
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"}));