322 lines · cpp
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 10using namespace clang::tidy::llvm_check;11 12namespace clang {13namespace tidy {14namespace test {15 16template <typename T>17static 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 33static std::string34runHeaderGuardCheck(StringRef Code, const Twine &Filename,35 std::optional<StringRef> ExpectedWarning) {36 return runCheck<LLVMHeaderGuardCheck>(Code, Filename,37 std::move(ExpectedWarning));38}39 40static std::string41runIncludeOrderCheck(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 51namespace {52struct WithEndifComment : public LLVMHeaderGuardCheck {53 WithEndifComment(StringRef Name, ClangTidyContext *Context)54 : LLVMHeaderGuardCheck(Name, Context) {}55 bool shouldSuggestEndifComment(StringRef Filename) override { return true; }56};57 58static std::string59runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename,60 std::optional<StringRef> ExpectedWarning) {61 return runCheck<WithEndifComment>(Code, Filename, std::move(ExpectedWarning));62}63} // namespace64 65TEST(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 starting252 // 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 WIN32262 // 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#endif300}301 302TEST(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 test320} // namespace tidy321} // namespace clang322