| //===---- IncludeInserterTest.cpp - clang-tidy ----------------------------===// | 
 | // | 
 | // 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-tidy/utils/IncludeInserter.h" | 
 | #include "clang/Lex/Preprocessor.h" | 
 | #include "clang/Frontend/CompilerInstance.h" | 
 | #include "ClangTidyTest.h" | 
 | #include "gtest/gtest.h" | 
 |  | 
 | // FIXME: Canonicalize paths correctly on windows. | 
 | // Currently, adding virtual files will canonicalize the paths before | 
 | // storing the virtual entries. | 
 | // When resolving virtual entries in the FileManager, the paths (for | 
 | // example coming from a #include directive) are not canonicalized | 
 | // to native paths; thus, the virtual file is not found. | 
 | // This needs to be fixed in the FileManager before we can make | 
 | // clang-tidy tests work. | 
 | #if !defined(_WIN32) | 
 |  | 
 | namespace clang { | 
 | namespace tidy { | 
 | namespace { | 
 |  | 
 | class IncludeInserterCheckBase : public ClangTidyCheck { | 
 | public: | 
 |   IncludeInserterCheckBase(StringRef CheckName, ClangTidyContext *Context, | 
 |                            utils::IncludeSorter::IncludeStyle Style = | 
 |                                utils::IncludeSorter::IS_Google, | 
 |                            bool SelfContainedDiags = false) | 
 |       : ClangTidyCheck(CheckName, Context), | 
 |         Inserter(Style, SelfContainedDiags) {} | 
 |  | 
 |   void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, | 
 |                            Preprocessor *ModuleExpanderPP) override { | 
 |     Inserter.registerPreprocessor(PP); | 
 |   } | 
 |  | 
 |   void registerMatchers(ast_matchers::MatchFinder *Finder) override { | 
 |     Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this); | 
 |   } | 
 |  | 
 |   void check(const ast_matchers::MatchFinder::MatchResult &Result) override { | 
 |     auto Diag = diag(Result.Nodes.getNodeAs<DeclStmt>("stmt")->getBeginLoc(), | 
 |                      "foo, bar"); | 
 |     for (StringRef Header : headersToInclude()) { | 
 |       Diag << Inserter.createMainFileIncludeInsertion(Header); | 
 |     } | 
 |   } | 
 |  | 
 |   virtual std::vector<StringRef> headersToInclude() const = 0; | 
 |  | 
 |   utils::IncludeInserter Inserter; | 
 | }; | 
 |  | 
 | class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   NonSystemHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"path/to/header.h"}; | 
 |   } | 
 | }; | 
 |  | 
 | class EarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   EarlyInAlphabetHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"a/header.h"}; | 
 |   } | 
 | }; | 
 |  | 
 | class MultipleHeaderInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   MultipleHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"}; | 
 |   } | 
 | }; | 
 |  | 
 | class MultipleHeaderSingleInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   MultipleHeaderSingleInserterCheck(StringRef CheckName, | 
 |                                     ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context, | 
 |                                  utils::IncludeSorter::IS_Google, | 
 |                                  /*SelfContainedDiags=*/true) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"}; | 
 |   } | 
 | }; | 
 |  | 
 | class CSystemIncludeInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   CSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"<stdlib.h>"}; | 
 |   } | 
 | }; | 
 |  | 
 | class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { return {"<set>"}; } | 
 | }; | 
 |  | 
 | class InvalidIncludeInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   InvalidIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"a.h", "<stdlib.h", "cstdlib>", "b.h", "<c.h>", "<d>"}; | 
 |   } | 
 | }; | 
 |  | 
 | class ObjCEarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   ObjCEarlyInAlphabetHeaderInserterCheck(StringRef CheckName, | 
 |                                          ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context, | 
 |                                  utils::IncludeSorter::IS_Google_ObjC) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"a/header.h"}; | 
 |   } | 
 | }; | 
 |  | 
 | class ObjCCategoryHeaderInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   ObjCCategoryHeaderInserterCheck(StringRef CheckName, | 
 |                                   ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context, | 
 |                                  utils::IncludeSorter::IS_Google_ObjC) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"top_level_test_header+foo.h"}; | 
 |   } | 
 | }; | 
 |  | 
 | class ObjCGeneratedHeaderInserterCheck : public IncludeInserterCheckBase { | 
 | public: | 
 |   ObjCGeneratedHeaderInserterCheck(StringRef CheckName, | 
 |                                    ClangTidyContext *Context) | 
 |       : IncludeInserterCheckBase(CheckName, Context, | 
 |                                  utils::IncludeSorter::IS_Google_ObjC) {} | 
 |  | 
 |   std::vector<StringRef> headersToInclude() const override { | 
 |     return {"clang_tidy/tests/generated_file.proto.h"}; | 
 |   } | 
 | }; | 
 |  | 
 | template <typename Check> | 
 | std::string runCheckOnCode(StringRef Code, StringRef Filename) { | 
 |   std::vector<ClangTidyError> Errors; | 
 |   return test::runCheckOnCode<Check>(Code, &Errors, Filename, std::nullopt, | 
 |                                      ClangTidyOptions(), | 
 |                                      {// Main file include | 
 |                                       {"clang_tidy/tests/" | 
 |                                        "insert_includes_test_header.h", | 
 |                                        "\n"}, | 
 |                                       // Top-level main file include + | 
 |                                       // category. | 
 |                                       {"top_level_test_header.h", "\n"}, | 
 |                                       {"top_level_test_header+foo.h", "\n"}, | 
 |                                       // ObjC category. | 
 |                                       {"clang_tidy/tests/" | 
 |                                        "insert_includes_test_header+foo.h", | 
 |                                        "\n"}, | 
 |                                       // Non system headers | 
 |                                       {"a/header.h", "\n"}, | 
 |                                       {"path/to/a/header.h", "\n"}, | 
 |                                       {"path/to/z/header.h", "\n"}, | 
 |                                       {"path/to/header.h", "\n"}, | 
 |                                       {"path/to/header2.h", "\n"}, | 
 |                                       // Generated headers | 
 |                                       {"clang_tidy/tests/" | 
 |                                        "generated_file.proto.h", | 
 |                                        "\n"}, | 
 |                                       // Fake system headers. | 
 |                                       {"stdlib.h", "\n"}, | 
 |                                       {"unistd.h", "\n"}, | 
 |                                       {"list", "\n"}, | 
 |                                       {"map", "\n"}, | 
 |                                       {"set", "\n"}, | 
 |                                       {"vector", "\n"}}); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<NonSystemHeaderInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertMultipleIncludesAndDeduplicate) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 | #include "path/to/header2.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<MultipleHeaderInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertMultipleIncludesNoDeduplicate) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   // FIXME: ClangFormat bug - https://bugs.llvm.org/show_bug.cgi?id=49298 | 
 |   // clang-format off | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 | #include "path/to/header2.h" | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   // clang-format on | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<MultipleHeaderSingleInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/z/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/header.h" | 
 | #include "path/to/z/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<NonSystemHeaderInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/z/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 | #include "path/to/z/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<NonSystemHeaderInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 | #include "path/to/z/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   EXPECT_EQ(PreCode, | 
 |             runCheckOnCode<NonSystemHeaderInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<NonSystemHeaderInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<NonSystemHeaderInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 | #include <set> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<CXXSystemIncludeInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <vector> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <set> | 
 | #include <vector> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<CXXSystemIncludeInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <map> | 
 | #include <vector> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <map> | 
 | #include <set> | 
 | #include <vector> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<CXXSystemIncludeInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <set> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<CXXSystemIncludeInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <stdlib.h> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <stdlib.h> | 
 |  | 
 | #include <set> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<CXXSystemIncludeInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include <set> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ( | 
 |       PostCode, | 
 |       runCheckOnCode<CXXSystemIncludeInserterCheck>( | 
 |           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) { | 
 |   const char *PreCode = R"( | 
 | #include <set> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include <stdlib.h> | 
 |  | 
 | #include <set> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ( | 
 |       PostCode, | 
 |       runCheckOnCode<CSystemIncludeInserterCheck>( | 
 |           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) { | 
 |   const char *PreCode = R"( | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"(#include <set> | 
 |  | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ( | 
 |       PostCode, | 
 |       runCheckOnCode<CXXSystemIncludeInserterCheck>( | 
 |           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, DontInsertDuplicateIncludeEvenIfMiscategorized) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <map> | 
 | #include <set> | 
 | #include <vector> | 
 |  | 
 | #include "a/header.h" | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <map> | 
 | #include <set> | 
 | #include <vector> | 
 |  | 
 | #include "a/header.h" | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>( | 
 |                           PreCode, "workspace_folder/clang_tidy/tests/" | 
 |                                    "insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, HandleOrderInSubdirectory) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <map> | 
 | #include <set> | 
 | #include <vector> | 
 |  | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <map> | 
 | #include <set> | 
 | #include <vector> | 
 |  | 
 | #include "a/header.h" | 
 | #include "path/to/a/header.h" | 
 | #include "path/to/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>( | 
 |                           PreCode, "workspace_folder/clang_tidy/tests/" | 
 |                                    "insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InvalidHeaderName) { | 
 |   const char *PreCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #include "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <c.h> | 
 |  | 
 | #include <d> | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "a.h" | 
 | #include "b.h" | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, | 
 |             runCheckOnCode<InvalidIncludeInserterCheck>( | 
 |                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertHeaderObjectiveC) { | 
 |   const char *PreCode = R"( | 
 | #import "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #import "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #import "a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ( | 
 |       PostCode, | 
 |       runCheckOnCode<ObjCEarlyInAlphabetHeaderInserterCheck>( | 
 |           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.mm")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertCategoryHeaderObjectiveC) { | 
 |   const char *PreCode = R"( | 
 | #import "top_level_test_header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #import "top_level_test_header.h" | 
 | #import "top_level_test_header+foo.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ(PostCode, runCheckOnCode<ObjCCategoryHeaderInserterCheck>( | 
 |                           PreCode, "top_level_test_header.mm")); | 
 | } | 
 |  | 
 | TEST(IncludeInserterTest, InsertGeneratedHeaderObjectiveC) { | 
 |   const char *PreCode = R"( | 
 | #import "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |   const char *PostCode = R"( | 
 | #import "clang_tidy/tests/insert_includes_test_header.h" | 
 |  | 
 | #include <list> | 
 | #include <map> | 
 |  | 
 | #include "path/to/a/header.h" | 
 |  | 
 | #import "clang_tidy/tests/generated_file.proto.h" | 
 |  | 
 | void foo() { | 
 |   int a = 0; | 
 | })"; | 
 |  | 
 |   EXPECT_EQ( | 
 |       PostCode, | 
 |       runCheckOnCode<ObjCGeneratedHeaderInserterCheck>( | 
 |           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.mm")); | 
 | } | 
 |  | 
 | } // anonymous namespace | 
 | } // namespace tidy | 
 | } // namespace clang | 
 |  | 
 | #endif |