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