xref: /llvm-project/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp (revision 649ef3386b90363af3c807ebe82d0facc75fa381)
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 
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
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 {
51   WithEndifComment(StringRef Name, ClangTidyContext *Context)
52       : LLVMHeaderGuardCheck(Name, Context) {}
53   bool shouldSuggestEndifComment(StringRef Filename) override { return true; }
54 };
55 
56 static std::string
57 runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename,
58                              Optional<StringRef> ExpectedWarning) {
59   return runCheck<WithEndifComment>(Code, Filename, std::move(ExpectedWarning));
60 }
61 } // namespace
62 
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", std::nullopt));
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",
188                                          std::nullopt));
189 
190   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n"
191             "#define LLVM_ADT_FOO_H_\n"
192             "#endif // LLVM_ADT_FOO_H_\n",
193             runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H_\n"
194                                          "#define LLVM_ADT_FOO_H_\n"
195                                          "#endif // LLVM_ADT_FOO_H_\n",
196                                          "include/llvm/ADT/foo.h",
197                                          std::nullopt));
198 
199   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
200             "#define LLVM_ADT_FOO_H\n"
201             "#endif // LLVM_ADT_FOO_H\n",
202             runHeaderGuardCheckWithEndif(
203                 "#ifndef LLVM_ADT_FOO_H_\n"
204                 "#define LLVM_ADT_FOO_H_\n"
205                 "#endif // LLVM\n",
206                 "include/llvm/ADT/foo.h",
207                 StringRef("header guard does not follow preferred style")));
208 
209   // An extra space inside the comment is OK.
210   llvm::StringRef WithExtraSpace = "#ifndef LLVM_ADT_FOO_H\n"
211                                    "#define LLVM_ADT_FOO_H\n"
212                                    "#endif //  LLVM_ADT_FOO_H\n";
213   EXPECT_EQ(WithExtraSpace,
214             runHeaderGuardCheckWithEndif(
215                 WithExtraSpace, "include/llvm/ADT/foo.h", std::nullopt));
216 
217   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
218             "#define LLVM_ADT_FOO_H\n"
219             "#endif \\ \n"
220             "// LLVM_ADT_FOO_H\n",
221             runHeaderGuardCheckWithEndif(
222                 "#ifndef LLVM_ADT_FOO_H\n"
223                 "#define LLVM_ADT_FOO_H\n"
224                 "#endif \\ \n"
225                 "// LLVM_ADT_FOO_H\n",
226                 "include/llvm/ADT/foo.h",
227                 StringRef("backslash and newline separated by space")));
228 
229   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
230             "#define LLVM_ADT_FOO_H\n"
231             "#endif  /* LLVM_ADT_FOO_H\\ \n"
232             " FOO */",
233             runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n"
234                                          "#define LLVM_ADT_FOO_H\n"
235                                          "#endif  /* LLVM_ADT_FOO_H\\ \n"
236                                          " FOO */",
237                                          "include/llvm/ADT/foo.h",
238                                          std::nullopt));
239 
240   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
241             "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
242             "\n"
243             "\n"
244             "#endif\n",
245             runHeaderGuardCheck(
246                 "", "/llvm-project/clang-tools-extra/clangd/foo.h",
247                 StringRef("header is missing header guard")));
248 
249   // Substitution of characters should not result in a header guard starting
250   // with "_".
251   EXPECT_EQ("#ifndef BAR_H\n"
252             "#define BAR_H\n"
253             "\n"
254             "\n"
255             "#endif\n",
256             runHeaderGuardCheck("", "include/--bar.h",
257                                 StringRef("header is missing header guard")));
258 
259 #ifdef WIN32
260   // Check interaction with Windows-style path separators (\).
261   EXPECT_EQ(
262       "#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
263       "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
264       "\n"
265       "\n"
266       "#endif\n",
267       runHeaderGuardCheck("", "llvm-project\\clang-tools-extra\\clangd\\foo.h",
268                           StringRef("header is missing header guard")));
269 
270   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
271             "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
272             "\n"
273             "\n"
274             "#endif\n",
275             runHeaderGuardCheck(
276                 "", "C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
277                 StringRef("header is missing header guard")));
278 
279   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
280             "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
281             "\n"
282             "\n"
283             "#endif\n",
284             runHeaderGuardCheck(
285                 "",
286                 "\\\\SMBShare\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
287                 StringRef("header is missing header guard")));
288 
289   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
290             "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
291             "\n"
292             "\n"
293             "#endif\n",
294             runHeaderGuardCheck(
295                 "", "\\\\?\\C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
296                 StringRef("header is missing header guard")));
297 #endif
298 }
299 
300 TEST(IncludeOrderCheck, GTestHeaders) {
301   EXPECT_EQ(
302       R"cpp(
303   #include "foo.h"
304   #include "llvm/foo.h"
305   #include "gtest/foo.h"
306   #include <algorithm>)cpp",
307       runIncludeOrderCheck(
308           R"cpp(
309   #include "foo.h"
310   #include "llvm/foo.h"
311   #include <algorithm>
312   #include "gtest/foo.h")cpp",
313           "foo.cc", StringRef("#includes are not sorted properly"),
314           {"foo.h", "algorithm", "gtest/foo.h", "llvm/foo.h"}));
315 }
316 
317 } // namespace test
318 } // namespace tidy
319 } // namespace clang
320