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.has_value()) 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", std::nullopt)); 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", 188 std::nullopt)); 189 190 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n" 191 "#define LLVM_ADT_FOO_H_\n" 192 "#endif // LLVM_ADT_FOO_H_\n", 193 runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H_\n" 194 "#define LLVM_ADT_FOO_H_\n" 195 "#endif // LLVM_ADT_FOO_H_\n", 196 "include/llvm/ADT/foo.h", 197 std::nullopt)); 198 199 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" 200 "#define LLVM_ADT_FOO_H\n" 201 "#endif // LLVM_ADT_FOO_H\n", 202 runHeaderGuardCheckWithEndif( 203 "#ifndef LLVM_ADT_FOO_H_\n" 204 "#define LLVM_ADT_FOO_H_\n" 205 "#endif // LLVM\n", 206 "include/llvm/ADT/foo.h", 207 StringRef("header guard does not follow preferred style"))); 208 209 // An extra space inside the comment is OK. 210 llvm::StringRef WithExtraSpace = "#ifndef LLVM_ADT_FOO_H\n" 211 "#define LLVM_ADT_FOO_H\n" 212 "#endif // LLVM_ADT_FOO_H\n"; 213 EXPECT_EQ(WithExtraSpace, 214 runHeaderGuardCheckWithEndif( 215 WithExtraSpace, "include/llvm/ADT/foo.h", std::nullopt)); 216 217 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" 218 "#define LLVM_ADT_FOO_H\n" 219 "#endif \\ \n" 220 "// LLVM_ADT_FOO_H\n", 221 runHeaderGuardCheckWithEndif( 222 "#ifndef LLVM_ADT_FOO_H\n" 223 "#define LLVM_ADT_FOO_H\n" 224 "#endif \\ \n" 225 "// LLVM_ADT_FOO_H\n", 226 "include/llvm/ADT/foo.h", 227 StringRef("backslash and newline separated by space"))); 228 229 EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" 230 "#define LLVM_ADT_FOO_H\n" 231 "#endif /* LLVM_ADT_FOO_H\\ \n" 232 " FOO */", 233 runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n" 234 "#define LLVM_ADT_FOO_H\n" 235 "#endif /* LLVM_ADT_FOO_H\\ \n" 236 " FOO */", 237 "include/llvm/ADT/foo.h", 238 std::nullopt)); 239 240 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 241 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 242 "\n" 243 "\n" 244 "#endif\n", 245 runHeaderGuardCheck( 246 "", "/llvm-project/clang-tools-extra/clangd/foo.h", 247 StringRef("header is missing header guard"))); 248 249 // Substitution of characters should not result in a header guard starting 250 // with "_". 251 EXPECT_EQ("#ifndef BAR_H\n" 252 "#define BAR_H\n" 253 "\n" 254 "\n" 255 "#endif\n", 256 runHeaderGuardCheck("", "include/--bar.h", 257 StringRef("header is missing header guard"))); 258 259 #ifdef WIN32 260 // Check interaction with Windows-style path separators (\). 261 EXPECT_EQ( 262 "#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("", "llvm-project\\clang-tools-extra\\clangd\\foo.h", 268 StringRef("header is missing header guard"))); 269 270 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 271 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 272 "\n" 273 "\n" 274 "#endif\n", 275 runHeaderGuardCheck( 276 "", "C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h", 277 StringRef("header is missing header guard"))); 278 279 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 280 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 281 "\n" 282 "\n" 283 "#endif\n", 284 runHeaderGuardCheck( 285 "", 286 "\\\\SMBShare\\llvm-project\\clang-tools-extra\\clangd\\foo.h", 287 StringRef("header is missing header guard"))); 288 289 EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 290 "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" 291 "\n" 292 "\n" 293 "#endif\n", 294 runHeaderGuardCheck( 295 "", "\\\\?\\C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h", 296 StringRef("header is missing header guard"))); 297 #endif 298 } 299 300 TEST(IncludeOrderCheck, GTestHeaders) { 301 EXPECT_EQ( 302 R"cpp( 303 #include "foo.h" 304 #include "llvm/foo.h" 305 #include "gtest/foo.h" 306 #include <algorithm>)cpp", 307 runIncludeOrderCheck( 308 R"cpp( 309 #include "foo.h" 310 #include "llvm/foo.h" 311 #include <algorithm> 312 #include "gtest/foo.h")cpp", 313 "foo.cc", StringRef("#includes are not sorted properly"), 314 {"foo.h", "algorithm", "gtest/foo.h", "llvm/foo.h"})); 315 } 316 317 } // namespace test 318 } // namespace tidy 319 } // namespace clang 320