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