| //===- unittest/Tooling/HeaderAnalysisTest.cpp ----------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Tooling/Inclusions/HeaderAnalysis.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "clang/Testing/TestAST.h" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| |
| namespace clang { |
| namespace tooling { |
| namespace { |
| using testing::Eq; |
| |
| TEST(HeaderAnalysisTest, IsSelfContained) { |
| TestInputs Inputs; |
| Inputs.Code = R"cpp( |
| #include "headerguard.h" |
| #include "pragmaonce.h" |
| #import "imported.h" |
| |
| #include "bad.h" |
| #include "unguarded.h" |
| )cpp"; |
| |
| Inputs.ExtraFiles["headerguard.h"] = R"cpp( |
| #ifndef HEADER_H |
| #define HEADER_H |
| |
| #endif HEADER_H |
| )cpp"; |
| Inputs.ExtraFiles["pragmaonce.h"] = R"cpp( |
| #pragma once |
| )cpp"; |
| Inputs.ExtraFiles["imported.h"] = ""; |
| |
| Inputs.ExtraFiles["unguarded.h"] = ""; |
| Inputs.ExtraFiles["bad.h"] = R"cpp( |
| #pragma once |
| |
| #if defined(INSIDE_H) |
| #error "Only ... can be included directly" |
| #endif |
| )cpp"; |
| |
| TestAST AST(Inputs); |
| const auto &SM = AST.sourceManager(); |
| auto &FM = SM.getFileManager(); |
| auto &HI = AST.preprocessor().getHeaderSearchInfo(); |
| EXPECT_TRUE( |
| isSelfContainedHeader(*FM.getOptionalFileRef("headerguard.h"), SM, HI)); |
| EXPECT_TRUE( |
| isSelfContainedHeader(*FM.getOptionalFileRef("pragmaonce.h"), SM, HI)); |
| EXPECT_TRUE( |
| isSelfContainedHeader(*FM.getOptionalFileRef("imported.h"), SM, HI)); |
| EXPECT_TRUE(isSelfContainedHeader( |
| *SM.getFileEntryRefForID(SM.getMainFileID()), SM, HI)); |
| |
| EXPECT_FALSE( |
| isSelfContainedHeader(*FM.getOptionalFileRef("unguarded.h"), SM, HI)); |
| EXPECT_FALSE(isSelfContainedHeader(*FM.getOptionalFileRef("bad.h"), SM, HI)); |
| } |
| |
| TEST(HeaderAnalysisTest, CodeContainsImports) { |
| EXPECT_TRUE(codeContainsImports(R"cpp( |
| #include "foo.h" |
| #import "NSFoo.h" |
| |
| int main() { |
| foo(); |
| } |
| )cpp")); |
| |
| EXPECT_TRUE(codeContainsImports(R"cpp( |
| #include "foo.h" |
| |
| int main() { |
| foo(); |
| } |
| |
| #import "NSFoo.h" |
| )cpp")); |
| |
| EXPECT_FALSE(codeContainsImports(R"cpp( |
| #include "foo.h" |
| |
| int main() { |
| foo(); |
| } |
| )cpp")); |
| } |
| |
| TEST(HeaderAnalysisTest, ParseIWYUPragma) { |
| EXPECT_THAT(parseIWYUPragma("// IWYU pragma: keep"), Eq("keep")); |
| EXPECT_THAT(parseIWYUPragma("// IWYU pragma: keep me\netc"), |
| Eq("keep me")); |
| EXPECT_THAT(parseIWYUPragma("/* IWYU pragma: keep */"), Eq("keep")); |
| EXPECT_EQ(parseIWYUPragma("// IWYU pragma: keep"), std::nullopt) |
| << "Prefix is sensitive to whitespace"; |
| EXPECT_EQ(parseIWYUPragma("// IWYU pragma:keep"), std::nullopt) |
| << "Prefix is sensitive to whitespace"; |
| EXPECT_EQ(parseIWYUPragma("/\n* IWYU pragma: keep */"), std::nullopt) |
| << "Must start with /* or //"; |
| } |
| |
| } // namespace |
| } // namespace tooling |
| } // namespace clang |