xref: /llvm-project/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp (revision f71ffd3b735b4d6ae3c12be1806cdd6205b3b378)
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                             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 
33 static std::string
runHeaderGuardCheck(StringRef Code,const Twine & Filename,std::optional<StringRef> ExpectedWarning)34 runHeaderGuardCheck(StringRef Code, const Twine &Filename,
35                     std::optional<StringRef> ExpectedWarning) {
36   return runCheck<LLVMHeaderGuardCheck>(Code, Filename,
37                                         std::move(ExpectedWarning));
38 }
39 
40 static std::string
runIncludeOrderCheck(StringRef Code,const Twine & Filename,std::optional<StringRef> ExpectedWarning,llvm::ArrayRef<llvm::StringLiteral> Includes)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),
48                                      PathsToContent);
49 }
50 
51 namespace {
52 struct WithEndifComment : public LLVMHeaderGuardCheck {
WithEndifCommentclang::tidy::test::__anoncb634f740111::WithEndifComment53   WithEndifComment(StringRef Name, ClangTidyContext *Context)
54       : LLVMHeaderGuardCheck(Name, Context) {}
shouldSuggestEndifCommentclang::tidy::test::__anoncb634f740111::WithEndifComment55   bool shouldSuggestEndifComment(StringRef Filename) override { return true; }
56 };
57 
58 static std::string
runHeaderGuardCheckWithEndif(StringRef Code,const Twine & Filename,std::optional<StringRef> ExpectedWarning)59 runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename,
60                              std::optional<StringRef> ExpectedWarning) {
61   return runCheck<WithEndifComment>(Code, Filename, std::move(ExpectedWarning));
62 }
63 } // namespace
64 
TEST(LLVMHeaderGuardCheckTest,FixHeaderGuards)65 TEST(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 
TEST(IncludeOrderCheck,GTestHeaders)302 TEST(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