1 #include "ClangTidyTest.h"
2 #include "llvm/HeaderGuardCheck.h"
3 #include "llvm/IncludeOrderCheck.h"
4 #include "gtest/gtest.h"
5 
6 using namespace clang::tidy::llvm_check;
7 
8 namespace clang {
9 namespace tidy {
10 namespace test {
11 
12 static std::string runHeaderGuardCheck(StringRef Code, const Twine &Filename,
13                                        Optional<StringRef> ExpectedWarning) {
14   std::vector<ClangTidyError> Errors;
15   std::string Result = test::runCheckOnCode<LLVMHeaderGuardCheck>(
16       Code, &Errors, Filename, std::string("-xc++-header"));
17   if (Errors.size() != (size_t)ExpectedWarning.hasValue())
18     return "invalid error count";
19   if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message)
20     return "expected: '" + ExpectedWarning->str() + "', saw: '" +
21            Errors.back().Message.Message + "'";
22   return Result;
23 }
24 
25 namespace {
26 struct WithEndifComment : public LLVMHeaderGuardCheck {
27   WithEndifComment(StringRef Name, ClangTidyContext *Context)
28       : LLVMHeaderGuardCheck(Name, Context) {}
29   bool shouldSuggestEndifComment(StringRef Filename) override { return true; }
30 };
31 } // namespace
32 
33 static std::string
34 runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename,
35                              Optional<StringRef> ExpectedWarning) {
36   std::vector<ClangTidyError> Errors;
37   std::string Result = test::runCheckOnCode<WithEndifComment>(
38       Code, &Errors, Filename, std::string("-xc++-header"));
39   if (Errors.size() != (size_t)ExpectedWarning.hasValue())
40     return "invalid error count";
41   if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message)
42     return "expected: '" + ExpectedWarning->str() + "', saw: '" +
43            Errors.back().Message.Message + "'";
44   return Result;
45 }
46 
47 TEST(LLVMHeaderGuardCheckTest, FixHeaderGuards) {
48   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
49             "#define LLVM_ADT_FOO_H\n"
50             "#endif\n",
51             runHeaderGuardCheck(
52                 "#ifndef FOO\n"
53                 "#define FOO\n"
54                 "#endif\n",
55                 "include/llvm/ADT/foo.h",
56                 StringRef("header guard does not follow preferred style")));
57 
58   // Allow trailing underscores.
59   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n"
60             "#define LLVM_ADT_FOO_H_\n"
61             "#endif\n",
62             runHeaderGuardCheck("#ifndef LLVM_ADT_FOO_H_\n"
63                                 "#define LLVM_ADT_FOO_H_\n"
64                                 "#endif\n",
65                                 "include/llvm/ADT/foo.h", None));
66 
67   EXPECT_EQ("#ifndef LLVM_CLANG_C_BAR_H\n"
68             "#define LLVM_CLANG_C_BAR_H\n"
69             "\n"
70             "\n"
71             "#endif\n",
72             runHeaderGuardCheck("", "./include/clang-c/bar.h",
73                                 StringRef("header is missing header guard")));
74 
75   EXPECT_EQ("#ifndef LLVM_CLANG_LIB_CODEGEN_C_H\n"
76             "#define LLVM_CLANG_LIB_CODEGEN_C_H\n"
77             "\n"
78             "\n"
79             "#endif\n",
80             runHeaderGuardCheck("", "tools/clang/lib/CodeGen/c.h",
81                                 StringRef("header is missing header guard")));
82 
83   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n"
84             "#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n"
85             "\n"
86             "\n"
87             "#endif\n",
88             runHeaderGuardCheck("", "tools/clang/tools/extra/clang-tidy/x.h",
89                                 StringRef("header is missing header guard")));
90 
91   EXPECT_EQ(
92       "int foo;\n"
93       "#ifndef LLVM_CLANG_BAR_H\n"
94       "#define LLVM_CLANG_BAR_H\n"
95       "#endif\n",
96       runHeaderGuardCheck("int foo;\n"
97                           "#ifndef LLVM_CLANG_BAR_H\n"
98                           "#define LLVM_CLANG_BAR_H\n"
99                           "#endif\n",
100                           "include/clang/bar.h",
101                           StringRef("code/includes outside of area guarded by "
102                                     "header guard; consider moving it")));
103 
104   EXPECT_EQ(
105       "#ifndef LLVM_CLANG_BAR_H\n"
106       "#define LLVM_CLANG_BAR_H\n"
107       "#endif\n"
108       "int foo;\n",
109       runHeaderGuardCheck("#ifndef LLVM_CLANG_BAR_H\n"
110                           "#define LLVM_CLANG_BAR_H\n"
111                           "#endif\n"
112                           "int foo;\n",
113                           "include/clang/bar.h",
114                           StringRef("code/includes outside of area guarded by "
115                                     "header guard; consider moving it")));
116 
117   EXPECT_EQ("#ifndef LLVM_CLANG_BAR_H\n"
118             "#define LLVM_CLANG_BAR_H\n"
119             "\n"
120             "int foo;\n"
121             "#ifndef FOOLOLO\n"
122             "#define FOOLOLO\n"
123             "#endif\n"
124             "\n"
125             "#endif\n",
126             runHeaderGuardCheck("int foo;\n"
127                                 "#ifndef FOOLOLO\n"
128                                 "#define FOOLOLO\n"
129                                 "#endif\n",
130                                 "include/clang/bar.h",
131                                 StringRef("header is missing header guard")));
132 
133   // Fix incorrect #endif comments even if we shouldn't add new ones.
134   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
135             "#define LLVM_ADT_FOO_H\n"
136             "#endif // LLVM_ADT_FOO_H\n",
137             runHeaderGuardCheck(
138                 "#ifndef FOO\n"
139                 "#define FOO\n"
140                 "#endif // FOO\n",
141                 "include/llvm/ADT/foo.h",
142                 StringRef("header guard does not follow preferred style")));
143 
144   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
145             "#define LLVM_ADT_FOO_H\n"
146             "#endif // LLVM_ADT_FOO_H\n",
147             runHeaderGuardCheckWithEndif(
148                 "#ifndef FOO\n"
149                 "#define FOO\n"
150                 "#endif\n",
151                 "include/llvm/ADT/foo.h",
152                 StringRef("header guard does not follow preferred style")));
153 
154   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
155             "#define LLVM_ADT_FOO_H\n"
156             "#endif // LLVM_ADT_FOO_H\n",
157             runHeaderGuardCheckWithEndif(
158                 "#ifndef LLVM_ADT_FOO_H\n"
159                 "#define LLVM_ADT_FOO_H\n"
160                 "#endif // LLVM_H\n",
161                 "include/llvm/ADT/foo.h",
162                 StringRef("#endif for a header guard should reference the "
163                           "guard macro in a comment")));
164 
165   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
166             "#define LLVM_ADT_FOO_H\n"
167             "#endif /* LLVM_ADT_FOO_H */\n",
168             runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n"
169                                          "#define LLVM_ADT_FOO_H\n"
170                                          "#endif /* LLVM_ADT_FOO_H */\n",
171                                          "include/llvm/ADT/foo.h", None));
172 
173   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n"
174             "#define LLVM_ADT_FOO_H_\n"
175             "#endif // LLVM_ADT_FOO_H_\n",
176             runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H_\n"
177                                          "#define LLVM_ADT_FOO_H_\n"
178                                          "#endif // LLVM_ADT_FOO_H_\n",
179                                          "include/llvm/ADT/foo.h", None));
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(
185                 "#ifndef LLVM_ADT_FOO_H_\n"
186                 "#define LLVM_ADT_FOO_H_\n"
187                 "#endif // LLVM\n",
188                 "include/llvm/ADT/foo.h",
189                 StringRef("header guard does not follow preferred style")));
190 
191   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
192             "#define LLVM_ADT_FOO_H\n"
193             "#endif \\ \n"
194             "// LLVM_ADT_FOO_H\n",
195             runHeaderGuardCheckWithEndif(
196                 "#ifndef LLVM_ADT_FOO_H\n"
197                 "#define LLVM_ADT_FOO_H\n"
198                 "#endif \\ \n"
199                 "// LLVM_ADT_FOO_H\n",
200                 "include/llvm/ADT/foo.h",
201                 StringRef("backslash and newline separated by space")));
202 
203   EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
204             "#define LLVM_ADT_FOO_H\n"
205             "#endif  /* LLVM_ADT_FOO_H\\ \n"
206             " FOO */",
207             runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n"
208                                          "#define LLVM_ADT_FOO_H\n"
209                                          "#endif  /* LLVM_ADT_FOO_H\\ \n"
210                                          " FOO */",
211                                          "include/llvm/ADT/foo.h", None));
212 
213   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
214             "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
215             "\n"
216             "\n"
217             "#endif\n",
218             runHeaderGuardCheck(
219                 "", "/llvm-project/clang-tools-extra/clangd/foo.h",
220                 StringRef("header is missing header guard")));
221 
222   // Substitution of characters should not result in a header guard starting
223   // with "_".
224   EXPECT_EQ("#ifndef BAR_H\n"
225             "#define BAR_H\n"
226             "\n"
227             "\n"
228             "#endif\n",
229             runHeaderGuardCheck("", "include/--bar.h",
230                                 StringRef("header is missing header guard")));
231 
232 #ifdef WIN32
233   // Check interaction with Windows-style path separators (\).
234   EXPECT_EQ(
235       "#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
236       "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
237       "\n"
238       "\n"
239       "#endif\n",
240       runHeaderGuardCheck("", "llvm-project\\clang-tools-extra\\clangd\\foo.h",
241                           StringRef("header is missing header guard")));
242 
243   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
244             "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
245             "\n"
246             "\n"
247             "#endif\n",
248             runHeaderGuardCheck(
249                 "", "C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
250                 StringRef("header is missing header guard")));
251 
252   EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
253             "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n"
254             "\n"
255             "\n"
256             "#endif\n",
257             runHeaderGuardCheck(
258                 "",
259                 "\\\\SMBShare\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
260                 StringRef("header is missing header guard")));
261 
262   EXPECT_EQ("#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(
268                 "", "\\\\?\\C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h",
269                 StringRef("header is missing header guard")));
270 #endif
271 }
272 
273 } // namespace test
274 } // namespace tidy
275 } // namespace clang
276