xref: /llvm-project/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp (revision 7cf97d62f40990c2f86f75eb5a1d9cf2bd9de71e)
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.hasValue())
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", 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 
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