| #include "ClangTidyTest.h" |
| #include "llvm/HeaderGuardCheck.h" |
| #include "llvm/IncludeOrderCheck.h" |
| #include "gtest/gtest.h" |
| |
| using namespace clang::tidy::llvm_check; |
| |
| namespace clang { |
| namespace tidy { |
| namespace test { |
| |
| static std::string runHeaderGuardCheck(StringRef Code, const Twine &Filename, |
| Optional<StringRef> ExpectedWarning) { |
| std::vector<ClangTidyError> Errors; |
| std::string Result = test::runCheckOnCode<LLVMHeaderGuardCheck>( |
| Code, &Errors, Filename, std::string("-xc++-header")); |
| if (Errors.size() != (size_t)ExpectedWarning.hasValue()) |
| return "invalid error count"; |
| if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message) |
| return "expected: '" + ExpectedWarning->str() + "', saw: '" + |
| Errors.back().Message.Message + "'"; |
| return Result; |
| } |
| |
| namespace { |
| struct WithEndifComment : public LLVMHeaderGuardCheck { |
| WithEndifComment(StringRef Name, ClangTidyContext *Context) |
| : LLVMHeaderGuardCheck(Name, Context) {} |
| bool shouldSuggestEndifComment(StringRef Filename) override { return true; } |
| }; |
| } // namespace |
| |
| static std::string |
| runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename, |
| Optional<StringRef> ExpectedWarning) { |
| std::vector<ClangTidyError> Errors; |
| std::string Result = test::runCheckOnCode<WithEndifComment>( |
| Code, &Errors, Filename, std::string("-xc++-header")); |
| if (Errors.size() != (size_t)ExpectedWarning.hasValue()) |
| return "invalid error count"; |
| if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message) |
| return "expected: '" + ExpectedWarning->str() + "', saw: '" + |
| Errors.back().Message.Message + "'"; |
| return Result; |
| } |
| |
| TEST(LLVMHeaderGuardCheckTest, FixHeaderGuards) { |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif\n", |
| runHeaderGuardCheck( |
| "#ifndef FOO\n" |
| "#define FOO\n" |
| "#endif\n", |
| "include/llvm/ADT/foo.h", |
| StringRef("header guard does not follow preferred style"))); |
| |
| // Allow trailing underscores. |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n" |
| "#define LLVM_ADT_FOO_H_\n" |
| "#endif\n", |
| runHeaderGuardCheck("#ifndef LLVM_ADT_FOO_H_\n" |
| "#define LLVM_ADT_FOO_H_\n" |
| "#endif\n", |
| "include/llvm/ADT/foo.h", None)); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_C_BAR_H\n" |
| "#define LLVM_CLANG_C_BAR_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck("", "./include/clang-c/bar.h", |
| StringRef("header is missing header guard"))); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_LIB_CODEGEN_C_H\n" |
| "#define LLVM_CLANG_LIB_CODEGEN_C_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck("", "tools/clang/lib/CodeGen/c.h", |
| StringRef("header is missing header guard"))); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n" |
| "#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck("", "tools/clang/tools/extra/clang-tidy/x.h", |
| StringRef("header is missing header guard"))); |
| |
| EXPECT_EQ( |
| "int foo;\n" |
| "#ifndef LLVM_CLANG_BAR_H\n" |
| "#define LLVM_CLANG_BAR_H\n" |
| "#endif\n", |
| runHeaderGuardCheck("int foo;\n" |
| "#ifndef LLVM_CLANG_BAR_H\n" |
| "#define LLVM_CLANG_BAR_H\n" |
| "#endif\n", |
| "include/clang/bar.h", |
| StringRef("code/includes outside of area guarded by " |
| "header guard; consider moving it"))); |
| |
| EXPECT_EQ( |
| "#ifndef LLVM_CLANG_BAR_H\n" |
| "#define LLVM_CLANG_BAR_H\n" |
| "#endif\n" |
| "int foo;\n", |
| runHeaderGuardCheck("#ifndef LLVM_CLANG_BAR_H\n" |
| "#define LLVM_CLANG_BAR_H\n" |
| "#endif\n" |
| "int foo;\n", |
| "include/clang/bar.h", |
| StringRef("code/includes outside of area guarded by " |
| "header guard; consider moving it"))); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_BAR_H\n" |
| "#define LLVM_CLANG_BAR_H\n" |
| "\n" |
| "int foo;\n" |
| "#ifndef FOOLOLO\n" |
| "#define FOOLOLO\n" |
| "#endif\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck("int foo;\n" |
| "#ifndef FOOLOLO\n" |
| "#define FOOLOLO\n" |
| "#endif\n", |
| "include/clang/bar.h", |
| StringRef("header is missing header guard"))); |
| |
| // Fix incorrect #endif comments even if we shouldn't add new ones. |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif // LLVM_ADT_FOO_H\n", |
| runHeaderGuardCheck( |
| "#ifndef FOO\n" |
| "#define FOO\n" |
| "#endif // FOO\n", |
| "include/llvm/ADT/foo.h", |
| StringRef("header guard does not follow preferred style"))); |
| |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif // LLVM_ADT_FOO_H\n", |
| runHeaderGuardCheckWithEndif( |
| "#ifndef FOO\n" |
| "#define FOO\n" |
| "#endif\n", |
| "include/llvm/ADT/foo.h", |
| StringRef("header guard does not follow preferred style"))); |
| |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif // LLVM_ADT_FOO_H\n", |
| runHeaderGuardCheckWithEndif( |
| "#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif // LLVM_H\n", |
| "include/llvm/ADT/foo.h", |
| StringRef("#endif for a header guard should reference the " |
| "guard macro in a comment"))); |
| |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif /* LLVM_ADT_FOO_H */\n", |
| runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif /* LLVM_ADT_FOO_H */\n", |
| "include/llvm/ADT/foo.h", None)); |
| |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n" |
| "#define LLVM_ADT_FOO_H_\n" |
| "#endif // LLVM_ADT_FOO_H_\n", |
| runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H_\n" |
| "#define LLVM_ADT_FOO_H_\n" |
| "#endif // LLVM_ADT_FOO_H_\n", |
| "include/llvm/ADT/foo.h", None)); |
| |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif // LLVM_ADT_FOO_H\n", |
| runHeaderGuardCheckWithEndif( |
| "#ifndef LLVM_ADT_FOO_H_\n" |
| "#define LLVM_ADT_FOO_H_\n" |
| "#endif // LLVM\n", |
| "include/llvm/ADT/foo.h", |
| StringRef("header guard does not follow preferred style"))); |
| |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif \\ \n" |
| "// LLVM_ADT_FOO_H\n", |
| runHeaderGuardCheckWithEndif( |
| "#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif \\ \n" |
| "// LLVM_ADT_FOO_H\n", |
| "include/llvm/ADT/foo.h", |
| StringRef("backslash and newline separated by space"))); |
| |
| EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif /* LLVM_ADT_FOO_H\\ \n" |
| " FOO */", |
| runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n" |
| "#define LLVM_ADT_FOO_H\n" |
| "#endif /* LLVM_ADT_FOO_H\\ \n" |
| " FOO */", |
| "include/llvm/ADT/foo.h", None)); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck( |
| "", "/llvm-project/clang-tools-extra/clangd/foo.h", |
| StringRef("header is missing header guard"))); |
| |
| // Substitution of characters should not result in a header guard starting |
| // with "_". |
| EXPECT_EQ("#ifndef BAR_H\n" |
| "#define BAR_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck("", "include/--bar.h", |
| StringRef("header is missing header guard"))); |
| |
| #ifdef WIN32 |
| // Check interaction with Windows-style path separators (\). |
| EXPECT_EQ( |
| "#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck("", "llvm-project\\clang-tools-extra\\clangd\\foo.h", |
| StringRef("header is missing header guard"))); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck( |
| "", "C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h", |
| StringRef("header is missing header guard"))); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck( |
| "", |
| "\\\\SMBShare\\llvm-project\\clang-tools-extra\\clangd\\foo.h", |
| StringRef("header is missing header guard"))); |
| |
| EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FOO_H\n" |
| "\n" |
| "\n" |
| "#endif\n", |
| runHeaderGuardCheck( |
| "", "\\\\?\\C:\\llvm-project\\clang-tools-extra\\clangd\\foo.h", |
| StringRef("header is missing header guard"))); |
| #endif |
| } |
| |
| } // namespace test |
| } // namespace tidy |
| } // namespace clang |