r360572 - [ASTImporter] Separate unittest files

Gabor Marton via cfe-commits cfe-commits at lists.llvm.org
Mon May 13 03:06:25 PDT 2019


Author: martong
Date: Mon May 13 03:06:25 2019
New Revision: 360572

URL: http://llvm.org/viewvc/llvm-project?rev=360572&view=rev
Log:
[ASTImporter] Separate unittest files

Summary:
Move generic redecl chain tests and visibility tests into their own
separate test files.

Reviewers: a_sidorin, a.sidorin, shafik

Subscribers: mgorny, rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D61786

Added:
    cfe/trunk/unittests/AST/ASTImporterFixtures.cpp
    cfe/trunk/unittests/AST/ASTImporterFixtures.h
    cfe/trunk/unittests/AST/ASTImporterGenericRedeclTest.cpp
    cfe/trunk/unittests/AST/ASTImporterVisibilityTest.cpp
Modified:
    cfe/trunk/unittests/AST/ASTImporterTest.cpp
    cfe/trunk/unittests/AST/CMakeLists.txt

Added: cfe/trunk/unittests/AST/ASTImporterFixtures.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterFixtures.cpp?rev=360572&view=auto
==============================================================================
--- cfe/trunk/unittests/AST/ASTImporterFixtures.cpp (added)
+++ cfe/trunk/unittests/AST/ASTImporterFixtures.cpp Mon May 13 03:06:25 2019
@@ -0,0 +1,210 @@
+//===- unittest/AST/ASTImporterFixtures.cpp - AST unit test support -------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Implementation of fixture classes for testing the ASTImporter.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTImporterFixtures.h"
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/ASTImporterLookupTable.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/Tooling.h"
+
+namespace clang {
+namespace ast_matchers {
+
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+                               std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {
+  assert(ToAST);
+  ASTContext &ToCtx = ToAST->getASTContext();
+  auto *OFS = static_cast<llvm::vfs::OverlayFileSystem *>(
+      &ToCtx.getSourceManager().getFileManager().getVirtualFileSystem());
+  auto *MFS = static_cast<llvm::vfs::InMemoryFileSystem *>(
+      OFS->overlays_begin()->get());
+  MFS->addFile(FileName, 0, std::move(Buffer));
+}
+
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+                               StringRef Code) {
+  return createVirtualFileIfNeeded(ToAST, FileName,
+                                   llvm::MemoryBuffer::getMemBuffer(Code));
+}
+
+ASTImporterTestBase::TU::TU(StringRef Code, StringRef FileName, ArgVector Args,
+                            ImporterConstructor C)
+    : Code(Code), FileName(FileName),
+      Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args, this->FileName)),
+      TUDecl(Unit->getASTContext().getTranslationUnitDecl()), Creator(C) {
+  Unit->enableSourceFileDiagnostics();
+
+  // If the test doesn't need a specific ASTImporter, we just create a
+  // normal ASTImporter with it.
+  if (!Creator)
+    Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
+                 ASTContext &FromContext, FileManager &FromFileManager,
+                 bool MinimalImport, ASTImporterLookupTable *LookupTable) {
+      return new ASTImporter(ToContext, ToFileManager, FromContext,
+                             FromFileManager, MinimalImport, LookupTable);
+    };
+}
+
+ASTImporterTestBase::TU::~TU() {}
+
+void ASTImporterTestBase::TU::lazyInitImporter(
+    ASTImporterLookupTable &LookupTable, ASTUnit *ToAST) {
+  assert(ToAST);
+  if (!Importer)
+    Importer.reset(Creator(ToAST->getASTContext(), ToAST->getFileManager(),
+                           Unit->getASTContext(), Unit->getFileManager(), false,
+                           &LookupTable));
+  assert(&ToAST->getASTContext() == &Importer->getToContext());
+  createVirtualFileIfNeeded(ToAST, FileName, Code);
+}
+
+Decl *ASTImporterTestBase::TU::import(ASTImporterLookupTable &LookupTable,
+                                      ASTUnit *ToAST, Decl *FromDecl) {
+  lazyInitImporter(LookupTable, ToAST);
+  if (auto ImportedOrErr = Importer->Import_New(FromDecl))
+    return *ImportedOrErr;
+  else {
+    llvm::consumeError(ImportedOrErr.takeError());
+    return nullptr;
+  }
+}
+
+QualType ASTImporterTestBase::TU::import(ASTImporterLookupTable &LookupTable,
+                                         ASTUnit *ToAST, QualType FromType) {
+  lazyInitImporter(LookupTable, ToAST);
+  if (auto ImportedOrErr = Importer->Import_New(FromType))
+    return *ImportedOrErr;
+  else {
+    llvm::consumeError(ImportedOrErr.takeError());
+    return QualType{};
+  }
+}
+
+void ASTImporterTestBase::lazyInitLookupTable(TranslationUnitDecl *ToTU) {
+  assert(ToTU);
+  if (!LookupTablePtr)
+    LookupTablePtr = llvm::make_unique<ASTImporterLookupTable>(*ToTU);
+}
+
+void ASTImporterTestBase::lazyInitToAST(Language ToLang, StringRef ToSrcCode,
+                                        StringRef FileName) {
+  if (ToAST)
+    return;
+  ArgVector ToArgs = getArgVectorForLanguage(ToLang);
+  // Source code must be a valid live buffer through the tests lifetime.
+  ToCode = ToSrcCode;
+  // Build the AST from an empty file.
+  ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, FileName);
+  ToAST->enableSourceFileDiagnostics();
+  lazyInitLookupTable(ToAST->getASTContext().getTranslationUnitDecl());
+}
+
+ASTImporterTestBase::TU *ASTImporterTestBase::findFromTU(Decl *From) {
+  // Create a virtual file in the To Ctx which corresponds to the file from
+  // which we want to import the `From` Decl. Without this source locations
+  // will be invalid in the ToCtx.
+  auto It = llvm::find_if(FromTUs, [From](const TU &E) {
+    return E.TUDecl == From->getTranslationUnitDecl();
+  });
+  assert(It != FromTUs.end());
+  return &*It;
+}
+
+std::tuple<Decl *, Decl *>
+ASTImporterTestBase::getImportedDecl(StringRef FromSrcCode, Language FromLang,
+                                     StringRef ToSrcCode, Language ToLang,
+                                     StringRef Identifier) {
+  ArgVector FromArgs = getArgVectorForLanguage(FromLang),
+            ToArgs = getArgVectorForLanguage(ToLang);
+
+  FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs, Creator);
+  TU &FromTU = FromTUs.back();
+
+  assert(!ToAST);
+  lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
+
+  ASTContext &FromCtx = FromTU.Unit->getASTContext();
+
+  IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);
+  assert(ImportedII && "Declaration with the given identifier "
+                       "should be specified in test!");
+  DeclarationName ImportDeclName(ImportedII);
+  SmallVector<NamedDecl *, 1> FoundDecls;
+  FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,
+                                                        FoundDecls);
+
+  assert(FoundDecls.size() == 1);
+
+  Decl *Imported =
+      FromTU.import(*LookupTablePtr, ToAST.get(), FoundDecls.front());
+
+  assert(Imported);
+  return std::make_tuple(*FoundDecls.begin(), Imported);
+}
+
+TranslationUnitDecl *ASTImporterTestBase::getTuDecl(StringRef SrcCode,
+                                                    Language Lang,
+                                                    StringRef FileName) {
+  assert(llvm::find_if(FromTUs, [FileName](const TU &E) {
+           return E.FileName == FileName;
+         }) == FromTUs.end());
+
+  ArgVector Args = getArgVectorForLanguage(Lang);
+  FromTUs.emplace_back(SrcCode, FileName, Args);
+  TU &Tu = FromTUs.back();
+
+  return Tu.TUDecl;
+}
+
+TranslationUnitDecl *ASTImporterTestBase::getToTuDecl(StringRef ToSrcCode,
+                                                      Language ToLang) {
+  ArgVector ToArgs = getArgVectorForLanguage(ToLang);
+  assert(!ToAST);
+  lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
+  return ToAST->getASTContext().getTranslationUnitDecl();
+}
+
+Decl *ASTImporterTestBase::Import(Decl *From, Language ToLang) {
+  lazyInitToAST(ToLang, "", OutputFileName);
+  TU *FromTU = findFromTU(From);
+  assert(LookupTablePtr);
+  return FromTU->import(*LookupTablePtr, ToAST.get(), From);
+}
+
+QualType ASTImporterTestBase::ImportType(QualType FromType, Decl *TUDecl,
+                                         Language ToLang) {
+  lazyInitToAST(ToLang, "", OutputFileName);
+  TU *FromTU = findFromTU(TUDecl);
+  assert(LookupTablePtr);
+  return FromTU->import(*LookupTablePtr, ToAST.get(), FromType);
+}
+
+ASTImporterTestBase::~ASTImporterTestBase() {
+  if (!::testing::Test::HasFailure())
+    return;
+
+  for (auto &Tu : FromTUs) {
+    assert(Tu.Unit);
+    llvm::errs() << "FromAST:\n";
+    Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();
+    llvm::errs() << "\n";
+  }
+  if (ToAST) {
+    llvm::errs() << "ToAST:\n";
+    ToAST->getASTContext().getTranslationUnitDecl()->dump();
+  }
+}
+
+} // end namespace ast_matchers
+} // end namespace clang

Added: cfe/trunk/unittests/AST/ASTImporterFixtures.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterFixtures.h?rev=360572&view=auto
==============================================================================
--- cfe/trunk/unittests/AST/ASTImporterFixtures.h (added)
+++ cfe/trunk/unittests/AST/ASTImporterFixtures.h Mon May 13 03:06:25 2019
@@ -0,0 +1,176 @@
+//===- unittest/AST/ASTImporterFixtures.h - AST unit test support ---------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Fixture classes for testing the ASTImporter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H
+#define LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H
+
+#include "gmock/gmock.h"
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/ASTImporterLookupTable.h"
+#include "clang/Frontend/ASTUnit.h"
+
+#include "DeclMatcher.h"
+#include "Language.h"
+
+namespace clang {
+
+class ASTImporter;
+class ASTImporterLookupTable;
+class ASTUnit;
+
+namespace ast_matchers {
+
+const StringRef DeclToImportID = "declToImport";
+const StringRef DeclToVerifyID = "declToVerify";
+
+// Creates a virtual file and assigns that to the context of given AST. If the
+// file already exists then the file will not be created again as a duplicate.
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+                               std::unique_ptr<llvm::MemoryBuffer> &&Buffer);
+
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+                               StringRef Code);
+
+// Common base for the different families of ASTImporter tests that are
+// parameterized on the compiler options which may result a different AST. E.g.
+// -fms-compatibility or -fdelayed-template-parsing.
+class CompilerOptionSpecificTest : public ::testing::Test {
+protected:
+  // Return the extra arguments appended to runtime options at compilation.
+  virtual ArgVector getExtraArgs() const { return ArgVector(); }
+
+  // Returns the argument vector used for a specific language option, this set
+  // can be tweaked by the test parameters.
+  ArgVector getArgVectorForLanguage(Language Lang) const {
+    ArgVector Args = getBasicRunOptionsForLanguage(Lang);
+    ArgVector ExtraArgs = getExtraArgs();
+    for (const auto &Arg : ExtraArgs) {
+      Args.push_back(Arg);
+    }
+    return Args;
+  }
+};
+
+const auto DefaultTestValuesForRunOptions = ::testing::Values(
+    ArgVector(), ArgVector{"-fdelayed-template-parsing"},
+    ArgVector{"-fms-compatibility"},
+    ArgVector{"-fdelayed-template-parsing", "-fms-compatibility"});
+
+// This class provides generic methods to write tests which can check internal
+// attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also,
+// this fixture makes it possible to import from several "From" contexts.
+class ASTImporterTestBase : public CompilerOptionSpecificTest {
+
+  const char *const InputFileName = "input.cc";
+  const char *const OutputFileName = "output.cc";
+
+public:
+  /// Allocates an ASTImporter (or one of its subclasses).
+  typedef std::function<ASTImporter *(ASTContext &, FileManager &, ASTContext &,
+                                      FileManager &, bool,
+                                      ASTImporterLookupTable *)>
+      ImporterConstructor;
+
+  // The lambda that constructs the ASTImporter we use in this test.
+  ImporterConstructor Creator;
+
+private:
+  // Buffer for the To context, must live in the test scope.
+  std::string ToCode;
+
+  // Represents a "From" translation unit and holds an importer object which we
+  // use to import from this translation unit.
+  struct TU {
+    // Buffer for the context, must live in the test scope.
+    std::string Code;
+    std::string FileName;
+    std::unique_ptr<ASTUnit> Unit;
+    TranslationUnitDecl *TUDecl = nullptr;
+    std::unique_ptr<ASTImporter> Importer;
+    ImporterConstructor Creator;
+
+    TU(StringRef Code, StringRef FileName, ArgVector Args,
+       ImporterConstructor C = ImporterConstructor());
+    ~TU();
+
+    void lazyInitImporter(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST);
+    Decl *import(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST,
+                 Decl *FromDecl);
+    QualType import(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST,
+                    QualType FromType);
+  };
+
+  // We may have several From contexts and related translation units. In each
+  // AST, the buffers for the source are handled via references and are set
+  // during the creation of the AST. These references must point to a valid
+  // buffer until the AST is alive. Thus, we must use a list in order to avoid
+  // moving of the stored objects because that would mean breaking the
+  // references in the AST. By using a vector a move could happen when the
+  // vector is expanding, with the list we won't have these issues.
+  std::list<TU> FromTUs;
+
+  // Initialize the lookup table if not initialized already.
+  void lazyInitLookupTable(TranslationUnitDecl *ToTU);
+
+  void lazyInitToAST(Language ToLang, StringRef ToSrcCode, StringRef FileName);
+  TU *findFromTU(Decl *From);
+
+protected:
+  std::unique_ptr<ASTImporterLookupTable> LookupTablePtr;
+
+public:
+  // We may have several From context but only one To context.
+  std::unique_ptr<ASTUnit> ToAST;
+
+  // Creates an AST both for the From and To source code and imports the Decl
+  // of the identifier into the To context.
+  // Must not be called more than once within the same test.
+  std::tuple<Decl *, Decl *>
+  getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode,
+                  Language ToLang, StringRef Identifier = DeclToImportID);
+
+  // Creates a TU decl for the given source code which can be used as a From
+  // context.  May be called several times in a given test (with different file
+  // name).
+  TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
+                                 StringRef FileName = "input.cc");
+
+  // Creates the To context with the given source code and returns the TU decl.
+  TranslationUnitDecl *getToTuDecl(StringRef ToSrcCode, Language ToLang);
+
+  // Import the given Decl into the ToCtx.
+  // May be called several times in a given test.
+  // The different instances of the param From may have different ASTContext.
+  Decl *Import(Decl *From, Language ToLang);
+
+  template <class DeclT> DeclT *Import(DeclT *From, Language Lang) {
+    return cast_or_null<DeclT>(Import(cast<Decl>(From), Lang));
+  }
+
+  QualType ImportType(QualType FromType, Decl *TUDecl, Language ToLang);
+
+  ~ASTImporterTestBase();
+};
+
+class ASTImporterOptionSpecificTestBase
+    : public ASTImporterTestBase,
+      public ::testing::WithParamInterface<ArgVector> {
+protected:
+  ArgVector getExtraArgs() const override { return GetParam(); }
+};
+
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif

Added: cfe/trunk/unittests/AST/ASTImporterGenericRedeclTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterGenericRedeclTest.cpp?rev=360572&view=auto
==============================================================================
--- cfe/trunk/unittests/AST/ASTImporterGenericRedeclTest.cpp (added)
+++ cfe/trunk/unittests/AST/ASTImporterGenericRedeclTest.cpp Mon May 13 03:06:25 2019
@@ -0,0 +1,577 @@
+//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Type-parameterized tests for the correct import of redecl chains.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTImporterFixtures.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using internal::BindableMatcher;
+
+struct Function {
+  using DeclTy = FunctionDecl;
+  static constexpr auto *Prototype = "void X();";
+  static constexpr auto *Definition = "void X() {}";
+  BindableMatcher<Decl> getPattern() {
+    return functionDecl(hasName("X"), unless(isImplicit()));
+  }
+};
+
+struct Class {
+  using DeclTy = CXXRecordDecl;
+  static constexpr auto *Prototype = "class X;";
+  static constexpr auto *Definition = "class X {};";
+  BindableMatcher<Decl> getPattern() {
+    return cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  }
+};
+
+struct Variable {
+  using DeclTy = VarDecl;
+  static constexpr auto *Prototype = "extern int X;";
+  static constexpr auto *Definition = "int X;";
+  BindableMatcher<Decl> getPattern() { return varDecl(hasName("X")); }
+};
+
+struct FunctionTemplate {
+  using DeclTy = FunctionTemplateDecl;
+  static constexpr auto *Prototype = "template <class T> void X();";
+  static constexpr auto *Definition =
+      R"(
+      template <class T> void X() {};
+      // Explicit instantiation is a must because of -fdelayed-template-parsing:
+      template void X<int>();
+      )";
+  BindableMatcher<Decl> getPattern() {
+    return functionTemplateDecl(hasName("X"), unless(isImplicit()));
+  }
+};
+
+struct ClassTemplate {
+  using DeclTy = ClassTemplateDecl;
+  static constexpr auto *Prototype = "template <class T> class X;";
+  static constexpr auto *Definition = "template <class T> class X {};";
+  BindableMatcher<Decl> getPattern() {
+    return classTemplateDecl(hasName("X"), unless(isImplicit()));
+  }
+};
+
+struct FunctionTemplateSpec {
+  using DeclTy = FunctionDecl;
+  static constexpr auto *Prototype =
+      R"(
+      // Proto of the primary template.
+      template <class T>
+      void X();
+      // Proto of the specialization.
+      template <>
+      void X<int>();
+      )";
+  static constexpr auto *Definition =
+      R"(
+      // Proto of the primary template.
+      template <class T>
+      void X();
+      // Specialization and definition.
+      template <>
+      void X<int>() {}
+      )";
+  BindableMatcher<Decl> getPattern() {
+    return functionDecl(hasName("X"), isExplicitTemplateSpecialization());
+  }
+};
+
+struct ClassTemplateSpec {
+  using DeclTy = ClassTemplateSpecializationDecl;
+  static constexpr auto *Prototype =
+      R"(
+    template <class T> class X;
+    template <> class X<int>;
+    )";
+  static constexpr auto *Definition =
+      R"(
+    template <class T> class X;
+    template <> class X<int> {};
+    )";
+  BindableMatcher<Decl> getPattern() {
+    return classTemplateSpecializationDecl(hasName("X"), unless(isImplicit()));
+  }
+};
+
+template <typename TypeParam>
+struct RedeclChain : ASTImporterOptionSpecificTestBase {
+
+  using DeclTy = typename TypeParam::DeclTy;
+  std::string getPrototype() { return TypeParam::Prototype; }
+  std::string getDefinition() { return TypeParam::Definition; }
+  BindableMatcher<Decl> getPattern() const { return TypeParam().getPattern(); }
+
+  void CheckPreviousDecl(Decl *Prev, Decl *Current) {
+    ASSERT_NE(Prev, Current);
+    ASSERT_EQ(&Prev->getASTContext(), &Current->getASTContext());
+    EXPECT_EQ(Prev->getCanonicalDecl(), Current->getCanonicalDecl());
+
+    // Templates.
+    if (auto *PrevT = dyn_cast<TemplateDecl>(Prev)) {
+      EXPECT_EQ(Current->getPreviousDecl(), Prev);
+      auto *CurrentT = cast<TemplateDecl>(Current);
+      ASSERT_TRUE(PrevT->getTemplatedDecl());
+      ASSERT_TRUE(CurrentT->getTemplatedDecl());
+      EXPECT_EQ(CurrentT->getTemplatedDecl()->getPreviousDecl(),
+                PrevT->getTemplatedDecl());
+      return;
+    }
+
+    // Specializations.
+    if (auto *PrevF = dyn_cast<FunctionDecl>(Prev)) {
+      if (PrevF->getTemplatedKind() ==
+          FunctionDecl::TK_FunctionTemplateSpecialization) {
+        // There may be a hidden fwd spec decl before a spec decl.
+        // In that case the previous visible decl can be reached through that
+        // invisible one.
+        EXPECT_THAT(Prev, testing::AnyOf(
+                              Current->getPreviousDecl(),
+                              Current->getPreviousDecl()->getPreviousDecl()));
+        auto *ToTU = Prev->getTranslationUnitDecl();
+        auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
+            ToTU, functionTemplateDecl());
+        auto *FirstSpecD = *(TemplateD->spec_begin());
+        EXPECT_EQ(FirstSpecD->getCanonicalDecl(), PrevF->getCanonicalDecl());
+        return;
+      }
+    }
+
+    // The rest: Classes, Functions, etc.
+    EXPECT_EQ(Current->getPreviousDecl(), Prev);
+  }
+
+  void
+  TypedTest_PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition() {
+    Decl *FromTU = getTuDecl(getPrototype(), Lang_CXX);
+    auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    ASSERT_FALSE(FromD->isThisDeclarationADefinition());
+
+    Decl *ImportedD = Import(FromD, Lang_CXX);
+    Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
+    auto *ToD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(ImportedD == ToD);
+    EXPECT_FALSE(ToD->isThisDeclarationADefinition());
+    if (auto *ToT = dyn_cast<TemplateDecl>(ToD)) {
+      EXPECT_TRUE(ToT->getTemplatedDecl());
+    }
+  }
+
+  void TypedTest_DefinitionShouldBeImportedAsADefinition() {
+    Decl *FromTU = getTuDecl(getDefinition(), Lang_CXX);
+    auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    ASSERT_TRUE(FromD->isThisDeclarationADefinition());
+
+    Decl *ImportedD = Import(FromD, Lang_CXX);
+    Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
+    auto *ToD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(ToD->isThisDeclarationADefinition());
+    if (auto *ToT = dyn_cast<TemplateDecl>(ToD)) {
+      EXPECT_TRUE(ToT->getTemplatedDecl());
+    }
+  }
+
+  void TypedTest_ImportPrototypeAfterImportedPrototype() {
+    Decl *FromTU = getTuDecl(getPrototype() + getPrototype(), Lang_CXX);
+    auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    auto *From1 = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    ASSERT_FALSE(From0->isThisDeclarationADefinition());
+    ASSERT_FALSE(From1->isThisDeclarationADefinition());
+
+    Decl *Imported0 = Import(From0, Lang_CXX);
+    Decl *Imported1 = Import(From1, Lang_CXX);
+    Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+    auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    auto *To1 = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(Imported0 == To0);
+    EXPECT_TRUE(Imported1 == To1);
+    EXPECT_FALSE(To0->isThisDeclarationADefinition());
+    EXPECT_FALSE(To1->isThisDeclarationADefinition());
+
+    CheckPreviousDecl(To0, To1);
+  }
+
+  void TypedTest_ImportDefinitionAfterImportedPrototype() {
+    Decl *FromTU = getTuDecl(getPrototype() + getDefinition(), Lang_CXX);
+    auto *FromProto = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    auto *FromDef = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+
+    Decl *ImportedProto = Import(FromProto, Lang_CXX);
+    Decl *ImportedDef = Import(FromDef, Lang_CXX);
+    Decl *ToTU = ImportedProto->getTranslationUnitDecl();
+
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+    auto *ToProto = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    auto *ToDef = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(ImportedProto == ToProto);
+    EXPECT_TRUE(ImportedDef == ToDef);
+    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+
+    CheckPreviousDecl(ToProto, ToDef);
+  }
+
+  void TypedTest_ImportPrototypeAfterImportedDefinition() {
+    Decl *FromTU = getTuDecl(getDefinition() + getPrototype(), Lang_CXX);
+    auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    auto *FromProto = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+
+    Decl *ImportedDef = Import(FromDef, Lang_CXX);
+    Decl *ImportedProto = Import(FromProto, Lang_CXX);
+    Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+    auto *ToDef = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    auto *ToProto = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(ImportedDef == ToDef);
+    EXPECT_TRUE(ImportedProto == ToProto);
+    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+
+    CheckPreviousDecl(ToDef, ToProto);
+  }
+
+  void TypedTest_ImportPrototypes() {
+    Decl *FromTU0 = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
+    Decl *FromTU1 = getTuDecl(getPrototype(), Lang_CXX, "input1.cc");
+    auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU0, getPattern());
+    auto *From1 = FirstDeclMatcher<DeclTy>().match(FromTU1, getPattern());
+    ASSERT_FALSE(From0->isThisDeclarationADefinition());
+    ASSERT_FALSE(From1->isThisDeclarationADefinition());
+
+    Decl *Imported0 = Import(From0, Lang_CXX);
+    Decl *Imported1 = Import(From1, Lang_CXX);
+    Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+    auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    auto *To1 = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(Imported0 == To0);
+    EXPECT_TRUE(Imported1 == To1);
+    EXPECT_FALSE(To0->isThisDeclarationADefinition());
+    EXPECT_FALSE(To1->isThisDeclarationADefinition());
+
+    CheckPreviousDecl(To0, To1);
+  }
+
+  void TypedTest_ImportDefinitions() {
+    Decl *FromTU0 = getTuDecl(getDefinition(), Lang_CXX, "input0.cc");
+    Decl *FromTU1 = getTuDecl(getDefinition(), Lang_CXX, "input1.cc");
+    auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU0, getPattern());
+    auto *From1 = FirstDeclMatcher<DeclTy>().match(FromTU1, getPattern());
+    ASSERT_TRUE(From0->isThisDeclarationADefinition());
+    ASSERT_TRUE(From1->isThisDeclarationADefinition());
+
+    Decl *Imported0 = Import(From0, Lang_CXX);
+    Decl *Imported1 = Import(From1, Lang_CXX);
+    Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+    EXPECT_EQ(Imported0, Imported1);
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
+    auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(Imported0 == To0);
+    EXPECT_TRUE(To0->isThisDeclarationADefinition());
+    if (auto *ToT0 = dyn_cast<TemplateDecl>(To0)) {
+      EXPECT_TRUE(ToT0->getTemplatedDecl());
+    }
+  }
+
+  void TypedTest_ImportDefinitionThenPrototype() {
+    Decl *FromTUDef = getTuDecl(getDefinition(), Lang_CXX, "input0.cc");
+    Decl *FromTUProto = getTuDecl(getPrototype(), Lang_CXX, "input1.cc");
+    auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTUDef, getPattern());
+    auto *FromProto =
+        FirstDeclMatcher<DeclTy>().match(FromTUProto, getPattern());
+    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+
+    Decl *ImportedDef = Import(FromDef, Lang_CXX);
+    Decl *ImportedProto = Import(FromProto, Lang_CXX);
+    Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+    EXPECT_NE(ImportedDef, ImportedProto);
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+    auto *ToDef = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    auto *ToProto = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(ImportedDef == ToDef);
+    EXPECT_TRUE(ImportedProto == ToProto);
+    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+
+    CheckPreviousDecl(ToDef, ToProto);
+  }
+
+  void TypedTest_ImportPrototypeThenDefinition() {
+    Decl *FromTUProto = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
+    Decl *FromTUDef = getTuDecl(getDefinition(), Lang_CXX, "input1.cc");
+    auto *FromProto =
+        FirstDeclMatcher<DeclTy>().match(FromTUProto, getPattern());
+    auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTUDef, getPattern());
+    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+
+    Decl *ImportedProto = Import(FromProto, Lang_CXX);
+    Decl *ImportedDef = Import(FromDef, Lang_CXX);
+    Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+    EXPECT_NE(ImportedDef, ImportedProto);
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+    auto *ToProto = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    auto *ToDef = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(ImportedDef == ToDef);
+    EXPECT_TRUE(ImportedProto == ToProto);
+    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+
+    CheckPreviousDecl(ToProto, ToDef);
+  }
+
+  void TypedTest_WholeRedeclChainIsImportedAtOnce() {
+    Decl *FromTU = getTuDecl(getPrototype() + getDefinition(), Lang_CXX);
+    auto *FromD = // Definition
+        LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+    ASSERT_TRUE(FromD->isThisDeclarationADefinition());
+
+    Decl *ImportedD = Import(FromD, Lang_CXX);
+    Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+    // The whole redecl chain is imported at once.
+    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+    EXPECT_TRUE(cast<DeclTy>(ImportedD)->isThisDeclarationADefinition());
+  }
+
+  void TypedTest_ImportPrototypeThenProtoAndDefinition() {
+    {
+      Decl *FromTU = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
+      auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+      Import(FromD, Lang_CXX);
+    }
+    {
+      Decl *FromTU =
+          getTuDecl(getPrototype() + getDefinition(), Lang_CXX, "input1.cc");
+      auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+      Import(FromD, Lang_CXX);
+    }
+
+    Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+    ASSERT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 3u);
+    DeclTy *ProtoD = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_FALSE(ProtoD->isThisDeclarationADefinition());
+
+    DeclTy *DefinitionD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+    EXPECT_TRUE(DefinitionD->isThisDeclarationADefinition());
+
+    EXPECT_TRUE(DefinitionD->getPreviousDecl());
+    EXPECT_FALSE(
+        DefinitionD->getPreviousDecl()->isThisDeclarationADefinition());
+
+    CheckPreviousDecl(ProtoD, DefinitionD->getPreviousDecl());
+  }
+};
+
+#define ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(BaseTemplate, TypeParam,       \
+                                                NamePrefix, TestCase)          \
+  using BaseTemplate##TypeParam = BaseTemplate<TypeParam>;                     \
+  TEST_P(BaseTemplate##TypeParam, NamePrefix##TestCase) {                      \
+    TypedTest_##TestCase();                                                    \
+  }
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, Function, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, Class, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, Variable, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, FunctionTemplate, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, ClassTemplate, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, FunctionTemplateSpec, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, ClassTemplateSpec, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+                                        DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        DefinitionShouldBeImportedAsADefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+                                        ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        ImportPrototypeAfterImportedPrototype)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+                                        ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        ImportDefinitionAfterImportedPrototype)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+                                        ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        ImportPrototypeAfterImportedDefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportPrototypes)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportDefinitions)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+                                        ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        ImportDefinitionThenPrototype)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+                                        ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+                                        ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+                                        ImportPrototypeThenDefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        WholeRedeclChainIsImportedAtOnce)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        WholeRedeclChainIsImportedAtOnce)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        WholeRedeclChainIsImportedAtOnce)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        WholeRedeclChainIsImportedAtOnce)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+                                        ImportPrototypeThenProtoAndDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+                                        ImportPrototypeThenProtoAndDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+                                        ImportPrototypeThenProtoAndDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+                                        ImportPrototypeThenProtoAndDefinition)
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunction,
+                        DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClass,
+                        DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainVariable,
+                        DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplate,
+                        DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplate,
+                        DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplateSpec,
+                        DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplateSpec,
+                        DefaultTestValuesForRunOptions, );
+
+} // end namespace ast_matchers
+} // end namespace clang

Modified: cfe/trunk/unittests/AST/ASTImporterTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterTest.cpp?rev=360572&r1=360571&r2=360572&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/ASTImporterTest.cpp (original)
+++ cfe/trunk/unittests/AST/ASTImporterTest.cpp Mon May 13 03:06:25 2019
@@ -10,24 +10,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-// Define this to have ::testing::Combine available.
-// FIXME: Better solution for this?
-#define GTEST_HAS_COMBINE 1
+#include "llvm/ADT/StringMap.h"
 
-#include "clang/AST/ASTImporter.h"
-#include "MatchVerifier.h"
-#include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclContextInternals.h"
-#include "clang/AST/ASTImporter.h"
-#include "clang/AST/ASTImporterLookupTable.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Tooling/Tooling.h"
-
-#include "DeclMatcher.h"
-#include "Language.h"
-#include "gmock/gmock.h"
-#include "llvm/ADT/StringMap.h"
+
+#include "ASTImporterFixtures.h"
+#include "MatchVerifier.h"
 
 namespace clang {
 namespace ast_matchers {
@@ -36,54 +24,6 @@ using internal::Matcher;
 using internal::BindableMatcher;
 using llvm::StringMap;
 
-// Creates a virtual file and assigns that to the context of given AST. If the
-// file already exists then the file will not be created again as a duplicate.
-static void
-createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
-                          std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {
-  assert(ToAST);
-  ASTContext &ToCtx = ToAST->getASTContext();
-  auto *OFS = static_cast<llvm::vfs::OverlayFileSystem *>(
-      &ToCtx.getSourceManager().getFileManager().getVirtualFileSystem());
-  auto *MFS = static_cast<llvm::vfs::InMemoryFileSystem *>(
-      OFS->overlays_begin()->get());
-  MFS->addFile(FileName, 0, std::move(Buffer));
-}
-
-static void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
-                                      StringRef Code) {
-  return createVirtualFileIfNeeded(ToAST, FileName,
-                                   llvm::MemoryBuffer::getMemBuffer(Code));
-}
-
-const StringRef DeclToImportID = "declToImport";
-const StringRef DeclToVerifyID = "declToVerify";
-
-// Common base for the different families of ASTImporter tests that are
-// parameterized on the compiler options which may result a different AST. E.g.
-// -fms-compatibility or -fdelayed-template-parsing.
-class CompilerOptionSpecificTest : public ::testing::Test {
-protected:
-  // Return the extra arguments appended to runtime options at compilation.
-  virtual ArgVector getExtraArgs() const { return ArgVector(); }
-
-  // Returns the argument vector used for a specific language option, this set
-  // can be tweaked by the test parameters.
-  ArgVector getArgVectorForLanguage(Language Lang) const {
-    ArgVector Args = getBasicRunOptionsForLanguage(Lang);
-    ArgVector ExtraArgs = getExtraArgs();
-    for (const auto &Arg : ExtraArgs) {
-      Args.push_back(Arg);
-    }
-    return Args;
-  }
-};
-
-auto DefaultTestValuesForRunOptions = ::testing::Values(
-    ArgVector(), ArgVector{"-fdelayed-template-parsing"},
-    ArgVector{"-fms-compatibility"},
-    ArgVector{"-fdelayed-template-parsing", "-fms-compatibility"});
-
 // Base class for those tests which use the family of `testImport` functions.
 class TestImportBase : public CompilerOptionSpecificTest,
                        public ::testing::WithParamInterface<ArgVector> {
@@ -305,239 +245,6 @@ template <typename T> RecordDecl *getRec
   return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
 }
 
-// This class provides generic methods to write tests which can check internal
-// attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also,
-// this fixture makes it possible to import from several "From" contexts.
-class ASTImporterTestBase : public CompilerOptionSpecificTest {
-
-  const char *const InputFileName = "input.cc";
-  const char *const OutputFileName = "output.cc";
-
-public:
-  /// Allocates an ASTImporter (or one of its subclasses).
-  typedef std::function<ASTImporter *(ASTContext &, FileManager &, ASTContext &,
-                                      FileManager &, bool,
-                                      ASTImporterLookupTable *)>
-      ImporterConstructor;
-
-  // The lambda that constructs the ASTImporter we use in this test.
-  ImporterConstructor Creator;
-
-private:
-  // Buffer for the To context, must live in the test scope.
-  std::string ToCode;
-
-  // Represents a "From" translation unit and holds an importer object which we
-  // use to import from this translation unit.
-  struct TU {
-    // Buffer for the context, must live in the test scope.
-    std::string Code;
-    std::string FileName;
-    std::unique_ptr<ASTUnit> Unit;
-    TranslationUnitDecl *TUDecl = nullptr;
-    std::unique_ptr<ASTImporter> Importer;
-    ImporterConstructor Creator;
-    TU(StringRef Code, StringRef FileName, ArgVector Args,
-       ImporterConstructor C = ImporterConstructor())
-        : Code(Code), FileName(FileName),
-          Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args,
-                                                 this->FileName)),
-          TUDecl(Unit->getASTContext().getTranslationUnitDecl()), Creator(C) {
-      Unit->enableSourceFileDiagnostics();
-
-      // If the test doesn't need a specific ASTImporter, we just create a
-      // normal ASTImporter with it.
-      if (!Creator)
-        Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
-                     ASTContext &FromContext, FileManager &FromFileManager,
-                     bool MinimalImport, ASTImporterLookupTable *LookupTable) {
-          return new ASTImporter(ToContext, ToFileManager, FromContext,
-                                 FromFileManager, MinimalImport, LookupTable);
-        };
-    }
-
-    void lazyInitImporter(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST) {
-      assert(ToAST);
-      if (!Importer)
-        Importer.reset(Creator(ToAST->getASTContext(), ToAST->getFileManager(),
-                               Unit->getASTContext(), Unit->getFileManager(),
-                               false, &LookupTable));
-      assert(&ToAST->getASTContext() == &Importer->getToContext());
-      createVirtualFileIfNeeded(ToAST, FileName, Code);
-    }
-
-    Decl *import(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST,
-                 Decl *FromDecl) {
-      lazyInitImporter(LookupTable, ToAST);
-      if (auto ImportedOrErr = Importer->Import_New(FromDecl))
-        return *ImportedOrErr;
-      else {
-        llvm::consumeError(ImportedOrErr.takeError());
-        return nullptr;
-      }
-    }
-
-    QualType import(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST,
-                    QualType FromType) {
-      lazyInitImporter(LookupTable, ToAST);
-      if (auto ImportedOrErr = Importer->Import_New(FromType))
-        return *ImportedOrErr;
-      else {
-        llvm::consumeError(ImportedOrErr.takeError());
-        return QualType{};
-      }
-    }
-  };
-
-  // We may have several From contexts and related translation units. In each
-  // AST, the buffers for the source are handled via references and are set
-  // during the creation of the AST. These references must point to a valid
-  // buffer until the AST is alive. Thus, we must use a list in order to avoid
-  // moving of the stored objects because that would mean breaking the
-  // references in the AST. By using a vector a move could happen when the
-  // vector is expanding, with the list we won't have these issues.
-  std::list<TU> FromTUs;
-
-  // Initialize the lookup table if not initialized already.
-  void lazyInitLookupTable(TranslationUnitDecl *ToTU) {
-    assert(ToTU);
-    if (!LookupTablePtr)
-      LookupTablePtr = llvm::make_unique<ASTImporterLookupTable>(*ToTU);
-  }
-
-  void lazyInitToAST(Language ToLang, StringRef ToSrcCode, StringRef FileName) {
-    if (ToAST)
-      return;
-    ArgVector ToArgs = getArgVectorForLanguage(ToLang);
-    // Source code must be a valid live buffer through the tests lifetime.
-    ToCode = ToSrcCode;
-    // Build the AST from an empty file.
-    ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, FileName);
-    ToAST->enableSourceFileDiagnostics();
-    lazyInitLookupTable(ToAST->getASTContext().getTranslationUnitDecl());
-  }
-
-  TU *findFromTU(Decl *From) {
-    // Create a virtual file in the To Ctx which corresponds to the file from
-    // which we want to import the `From` Decl. Without this source locations
-    // will be invalid in the ToCtx.
-    auto It = llvm::find_if(FromTUs, [From](const TU &E) {
-      return E.TUDecl == From->getTranslationUnitDecl();
-    });
-    assert(It != FromTUs.end());
-    return &*It;
-  }
-
-protected:
-
-  std::unique_ptr<ASTImporterLookupTable> LookupTablePtr;
-
-public:
-  // We may have several From context but only one To context.
-  std::unique_ptr<ASTUnit> ToAST;
-
-  // Creates an AST both for the From and To source code and imports the Decl
-  // of the identifier into the To context.
-  // Must not be called more than once within the same test.
-  std::tuple<Decl *, Decl *>
-  getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode,
-                  Language ToLang, StringRef Identifier = DeclToImportID) {
-    ArgVector FromArgs = getArgVectorForLanguage(FromLang),
-              ToArgs = getArgVectorForLanguage(ToLang);
-
-    FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs, Creator);
-    TU &FromTU = FromTUs.back();
-
-    assert(!ToAST);
-    lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
-
-    ASTContext &FromCtx = FromTU.Unit->getASTContext();
-
-    IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);
-    assert(ImportedII && "Declaration with the given identifier "
-                         "should be specified in test!");
-    DeclarationName ImportDeclName(ImportedII);
-    SmallVector<NamedDecl *, 1> FoundDecls;
-    FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,
-                                                          FoundDecls);
-
-    assert(FoundDecls.size() == 1);
-
-    Decl *Imported =
-        FromTU.import(*LookupTablePtr, ToAST.get(), FoundDecls.front());
-
-    assert(Imported);
-    return std::make_tuple(*FoundDecls.begin(), Imported);
-  }
-
-  // Creates a TU decl for the given source code which can be used as a From
-  // context.  May be called several times in a given test (with different file
-  // name).
-  TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
-                                 StringRef FileName = "input.cc") {
-    assert(llvm::find_if(FromTUs, [FileName](const TU &E) {
-             return E.FileName == FileName;
-           }) == FromTUs.end());
-
-    ArgVector Args = getArgVectorForLanguage(Lang);
-    FromTUs.emplace_back(SrcCode, FileName, Args);
-    TU &Tu = FromTUs.back();
-
-    return Tu.TUDecl;
-  }
-
-  // Creates the To context with the given source code and returns the TU decl.
-  TranslationUnitDecl *getToTuDecl(StringRef ToSrcCode, Language ToLang) {
-    ArgVector ToArgs = getArgVectorForLanguage(ToLang);
-    assert(!ToAST);
-    lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
-    return ToAST->getASTContext().getTranslationUnitDecl();
-  }
-
-  // Import the given Decl into the ToCtx.
-  // May be called several times in a given test.
-  // The different instances of the param From may have different ASTContext.
-  Decl *Import(Decl *From, Language ToLang) {
-    lazyInitToAST(ToLang, "", OutputFileName);
-    TU *FromTU = findFromTU(From);
-    assert(LookupTablePtr);
-    return FromTU->import(*LookupTablePtr, ToAST.get(), From);
-  }
-
-  template <class DeclT> DeclT *Import(DeclT *From, Language Lang) {
-    return cast_or_null<DeclT>(Import(cast<Decl>(From), Lang));
-  }
-
-  QualType ImportType(QualType FromType, Decl *TUDecl, Language ToLang) {
-    lazyInitToAST(ToLang, "", OutputFileName);
-    TU *FromTU = findFromTU(TUDecl);
-    assert(LookupTablePtr);
-    return FromTU->import(*LookupTablePtr, ToAST.get(), FromType);
-   }
-
-  ~ASTImporterTestBase() {
-    if (!::testing::Test::HasFailure()) return;
-
-    for (auto &Tu : FromTUs) {
-      assert(Tu.Unit);
-      llvm::errs() << "FromAST:\n";
-      Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();
-      llvm::errs() << "\n";
-    }
-    if (ToAST) {
-      llvm::errs() << "ToAST:\n";
-      ToAST->getASTContext().getTranslationUnitDecl()->dump();
-    }
-  }
-};
-
-class ASTImporterOptionSpecificTestBase
-    : public ASTImporterTestBase,
-      public ::testing::WithParamInterface<ArgVector> {
-protected:
-  ArgVector getExtraArgs() const override { return GetParam(); }
-};
-
 struct ImportExpr : TestImportBase {};
 struct ImportType : TestImportBase {};
 struct ImportDecl : TestImportBase {};
@@ -2451,206 +2158,6 @@ TEST_P(ImportFunctions,
   EXPECT_EQ(ToDFOutOfClass->getPreviousDecl(), ToDFInClass);
 }
 
-//FIXME Move these tests to a separate test file.
-namespace TypeAndValueParameterizedTests {
-
-// Type parameters for type-parameterized test fixtures.
-struct GetFunPattern {
-  using DeclTy = FunctionDecl;
-  BindableMatcher<Decl> operator()() { return functionDecl(hasName("f")); }
-};
-struct GetVarPattern {
-  using DeclTy = VarDecl;
-  BindableMatcher<Decl> operator()() { return varDecl(hasName("v")); }
-};
-
-// Values for the value-parameterized test fixtures.
-// FunctionDecl:
-auto *ExternF = "void f();";
-auto *StaticF = "static void f();";
-auto *AnonF = "namespace { void f(); }";
-// VarDecl:
-auto *ExternV = "extern int v;";
-auto *StaticV = "static int v;";
-auto *AnonV = "namespace { extern int v; }";
-
-// First value in tuple: Compile options.
-// Second value in tuple: Source code to be used in the test.
-using ImportVisibilityChainParams =
-    ::testing::WithParamInterface<std::tuple<ArgVector, const char *>>;
-// Fixture to test the redecl chain of Decls with the same visibility.  Gtest
-// makes it possible to have either value-parameterized or type-parameterized
-// fixtures.  However, we cannot have both value- and type-parameterized test
-// fixtures.  This is a value-parameterized test fixture in the gtest sense. We
-// intend to mimic gtest's type-parameters via the PatternFactory template
-// parameter.  We manually instantiate the different tests with the each types.
-template <typename PatternFactory>
-class ImportVisibilityChain
-    : public ASTImporterTestBase, public ImportVisibilityChainParams {
-protected:
-  using DeclTy = typename PatternFactory::DeclTy;
-  ArgVector getExtraArgs() const override { return std::get<0>(GetParam()); }
-  std::string getCode() const { return std::get<1>(GetParam()); }
-  BindableMatcher<Decl> getPattern() const { return PatternFactory()(); }
-
-  // Type-parameterized test.
-  void TypedTest_ImportChain() {
-    std::string Code = getCode() + getCode();
-    auto Pattern = getPattern();
-
-    TranslationUnitDecl *FromTu = getTuDecl(Code, Lang_CXX, "input0.cc");
-
-    auto *FromF0 = FirstDeclMatcher<DeclTy>().match(FromTu, Pattern);
-    auto *FromF1 = LastDeclMatcher<DeclTy>().match(FromTu, Pattern);
-
-    auto *ToF0 = Import(FromF0, Lang_CXX);
-    auto *ToF1 = Import(FromF1, Lang_CXX);
-
-    EXPECT_TRUE(ToF0);
-    ASSERT_TRUE(ToF1);
-    EXPECT_NE(ToF0, ToF1);
-    EXPECT_EQ(ToF1->getPreviousDecl(), ToF0);
-  }
-};
-
-// Manual instantiation of the fixture with each type.
-using ImportFunctionsVisibilityChain = ImportVisibilityChain<GetFunPattern>;
-using ImportVariablesVisibilityChain = ImportVisibilityChain<GetVarPattern>;
-// Value-parameterized test for the first type.
-TEST_P(ImportFunctionsVisibilityChain, ImportChain) {
-  TypedTest_ImportChain();
-}
-// Value-parameterized test for the second type.
-TEST_P(ImportVariablesVisibilityChain, ImportChain) {
-  TypedTest_ImportChain();
-}
-
-// Automatic instantiation of the value-parameterized tests.
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctionsVisibilityChain,
-                        ::testing::Combine(
-                           DefaultTestValuesForRunOptions,
-                           ::testing::Values(ExternF, StaticF, AnonF)), );
-INSTANTIATE_TEST_CASE_P(
-    ParameterizedTests, ImportVariablesVisibilityChain,
-    ::testing::Combine(
-        DefaultTestValuesForRunOptions,
-        // There is no point to instantiate with StaticV, because in C++ we can
-        // forward declare a variable only with the 'extern' keyword.
-        // Consequently, each fwd declared variable has external linkage.  This
-        // is different in the C language where any declaration without an
-        // initializer is a tentative definition, subsequent definitions may be
-        // provided but they must have the same linkage.  See also the test
-        // ImportVariableChainInC which test for this special C Lang case.
-        ::testing::Values(ExternV, AnonV)), );
-
-// First value in tuple: Compile options.
-// Second value in tuple: Tuple with informations for the test.
-// Code for first import (or initial code), code to import, whether the `f`
-// functions are expected to be linked in a declaration chain.
-// One value of this tuple is combined with every value of compile options.
-// The test can have a single tuple as parameter only.
-using ImportVisibilityParams = ::testing::WithParamInterface<
-    std::tuple<ArgVector, std::tuple<const char *, const char *, bool>>>;
-
-template <typename PatternFactory>
-class ImportVisibility
-    : public ASTImporterTestBase,
-      public ImportVisibilityParams {
-protected:
-  using DeclTy = typename PatternFactory::DeclTy;
-  ArgVector getExtraArgs() const override { return std::get<0>(GetParam()); }
-  std::string getCode0() const { return std::get<0>(std::get<1>(GetParam())); }
-  std::string getCode1() const { return std::get<1>(std::get<1>(GetParam())); }
-  bool shouldBeLinked() const { return std::get<2>(std::get<1>(GetParam())); }
-  BindableMatcher<Decl> getPattern() const { return PatternFactory()(); }
-
-  void TypedTest_ImportAfter() {
-    TranslationUnitDecl *ToTu = getToTuDecl(getCode0(), Lang_CXX);
-    TranslationUnitDecl *FromTu = getTuDecl(getCode1(), Lang_CXX, "input1.cc");
-
-    auto *ToF0 = FirstDeclMatcher<DeclTy>().match(ToTu, getPattern());
-    auto *FromF1 = FirstDeclMatcher<DeclTy>().match(FromTu, getPattern());
-
-    auto *ToF1 = Import(FromF1, Lang_CXX);
-
-    ASSERT_TRUE(ToF0);
-    ASSERT_TRUE(ToF1);
-    EXPECT_NE(ToF0, ToF1);
-
-    if (shouldBeLinked())
-      EXPECT_EQ(ToF1->getPreviousDecl(), ToF0);
-    else
-      EXPECT_FALSE(ToF1->getPreviousDecl());
-  }
-
-  void TypedTest_ImportAfterImport() {
-    TranslationUnitDecl *FromTu0 = getTuDecl(getCode0(), Lang_CXX, "input0.cc");
-    TranslationUnitDecl *FromTu1 = getTuDecl(getCode1(), Lang_CXX, "input1.cc");
-    auto *FromF0 =
-        FirstDeclMatcher<DeclTy>().match(FromTu0, getPattern());
-    auto *FromF1 =
-        FirstDeclMatcher<DeclTy>().match(FromTu1, getPattern());
-    auto *ToF0 = Import(FromF0, Lang_CXX);
-    auto *ToF1 = Import(FromF1, Lang_CXX);
-    ASSERT_TRUE(ToF0);
-    ASSERT_TRUE(ToF1);
-    EXPECT_NE(ToF0, ToF1);
-    if (shouldBeLinked())
-      EXPECT_EQ(ToF1->getPreviousDecl(), ToF0);
-    else
-      EXPECT_FALSE(ToF1->getPreviousDecl());
-  }
-};
-using ImportFunctionsVisibility = ImportVisibility<GetFunPattern>;
-using ImportVariablesVisibility = ImportVisibility<GetVarPattern>;
-
-// FunctionDecl.
-TEST_P(ImportFunctionsVisibility, ImportAfter) {
-  TypedTest_ImportAfter();
-}
-TEST_P(ImportFunctionsVisibility, ImportAfterImport) {
-  TypedTest_ImportAfterImport();
-}
-// VarDecl.
-TEST_P(ImportVariablesVisibility, ImportAfter) {
-  TypedTest_ImportAfter();
-}
-TEST_P(ImportVariablesVisibility, ImportAfterImport) {
-  TypedTest_ImportAfterImport();
-}
-
-bool ExpectLink = true;
-bool ExpectNotLink = false;
-
-INSTANTIATE_TEST_CASE_P(
-    ParameterizedTests, ImportFunctionsVisibility,
-    ::testing::Combine(
-        DefaultTestValuesForRunOptions,
-        ::testing::Values(std::make_tuple(ExternF, ExternF, ExpectLink),
-                          std::make_tuple(ExternF, StaticF, ExpectNotLink),
-                          std::make_tuple(ExternF, AnonF, ExpectNotLink),
-                          std::make_tuple(StaticF, ExternF, ExpectNotLink),
-                          std::make_tuple(StaticF, StaticF, ExpectNotLink),
-                          std::make_tuple(StaticF, AnonF, ExpectNotLink),
-                          std::make_tuple(AnonF, ExternF, ExpectNotLink),
-                          std::make_tuple(AnonF, StaticF, ExpectNotLink),
-                          std::make_tuple(AnonF, AnonF, ExpectNotLink))), );
-INSTANTIATE_TEST_CASE_P(
-    ParameterizedTests, ImportVariablesVisibility,
-    ::testing::Combine(
-        DefaultTestValuesForRunOptions,
-        ::testing::Values(std::make_tuple(ExternV, ExternV, ExpectLink),
-                          std::make_tuple(ExternV, StaticV, ExpectNotLink),
-                          std::make_tuple(ExternV, AnonV, ExpectNotLink),
-                          std::make_tuple(StaticV, ExternV, ExpectNotLink),
-                          std::make_tuple(StaticV, StaticV, ExpectNotLink),
-                          std::make_tuple(StaticV, AnonV, ExpectNotLink),
-                          std::make_tuple(AnonV, ExternV, ExpectNotLink),
-                          std::make_tuple(AnonV, StaticV, ExpectNotLink),
-                          std::make_tuple(AnonV, AnonV, ExpectNotLink))), );
-
-} // namespace TypeAndValueParameterizedTests
-
 TEST_P(ASTImporterOptionSpecificTestBase, ImportVariableChainInC) {
     std::string Code = "static int v; static int v = 0;";
     auto Pattern = varDecl(hasName("v"));
@@ -3983,574 +3490,6 @@ TEST_P(ImportClasses, ImportNestedProtot
   EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
 }
 
-// FIXME put these structs and the tests rely on them into their own separate
-// test file!
-struct Function {
-  using DeclTy = FunctionDecl;
-  static constexpr auto *Prototype = "void X();";
-  static constexpr auto *Definition = "void X() {}";
-  BindableMatcher<Decl> getPattern() {
-    return functionDecl(hasName("X"), unless(isImplicit()));
-  }
-};
-
-struct Class {
-  using DeclTy = CXXRecordDecl;
-  static constexpr auto *Prototype = "class X;";
-  static constexpr auto *Definition = "class X {};";
-  BindableMatcher<Decl> getPattern() {
-    return cxxRecordDecl(hasName("X"), unless(isImplicit()));
-  }
-};
-
-struct Variable {
-  using DeclTy = VarDecl;
-  static constexpr auto *Prototype = "extern int X;";
-  static constexpr auto *Definition = "int X;";
-  BindableMatcher<Decl> getPattern() {
-    return varDecl(hasName("X"));
-  }
-};
-
-struct FunctionTemplate {
-  using DeclTy = FunctionTemplateDecl;
-  static constexpr auto *Prototype = "template <class T> void X();";
-  static constexpr auto *Definition =
-      R"(
-      template <class T> void X() {};
-      // Explicit instantiation is a must because of -fdelayed-template-parsing:
-      template void X<int>();
-      )";
-  BindableMatcher<Decl> getPattern() {
-    return functionTemplateDecl(hasName("X"), unless(isImplicit()));
-  }
-};
-
-struct ClassTemplate {
-  using DeclTy = ClassTemplateDecl;
-  static constexpr auto *Prototype = "template <class T> class X;";
-  static constexpr auto *Definition = "template <class T> class X {};";
-  BindableMatcher<Decl> getPattern() {
-    return classTemplateDecl(hasName("X"), unless(isImplicit()));
-  }
-};
-
-struct FunctionTemplateSpec {
-  using DeclTy = FunctionDecl;
-  static constexpr auto *Prototype =
-      R"(
-      // Proto of the primary template.
-      template <class T>
-      void X();
-      // Proto of the specialization.
-      template <>
-      void X<int>();
-      )";
-  static constexpr auto *Definition =
-      R"(
-      // Proto of the primary template.
-      template <class T>
-      void X();
-      // Specialization and definition.
-      template <>
-      void X<int>() {}
-      )";
-  BindableMatcher<Decl> getPattern() {
-    return functionDecl(hasName("X"), isExplicitTemplateSpecialization());
-  }
-};
-
-struct ClassTemplateSpec {
-  using DeclTy = ClassTemplateSpecializationDecl;
-  static constexpr auto *Prototype =
-    R"(
-    template <class T> class X;
-    template <> class X<int>;
-    )";
-  static constexpr auto *Definition =
-    R"(
-    template <class T> class X;
-    template <> class X<int> {};
-    )";
-  BindableMatcher<Decl> getPattern() {
-    return classTemplateSpecializationDecl(hasName("X"), unless(isImplicit()));
-  }
-};
-
-template <typename TypeParam>
-struct RedeclChain : ASTImporterOptionSpecificTestBase {
-
-  using DeclTy = typename TypeParam::DeclTy;
-  std::string getPrototype() { return TypeParam::Prototype; }
-  std::string getDefinition() { return TypeParam::Definition; }
-  BindableMatcher<Decl> getPattern() const { return TypeParam().getPattern(); }
-
-  void CheckPreviousDecl(Decl *Prev, Decl *Current) {
-    ASSERT_NE(Prev, Current);
-    ASSERT_EQ(&Prev->getASTContext(), &Current->getASTContext());
-    EXPECT_EQ(Prev->getCanonicalDecl(), Current->getCanonicalDecl());
-
-    // Templates.
-    if (auto *PrevT = dyn_cast<TemplateDecl>(Prev)) {
-      EXPECT_EQ(Current->getPreviousDecl(), Prev);
-      auto *CurrentT = cast<TemplateDecl>(Current);
-      ASSERT_TRUE(PrevT->getTemplatedDecl());
-      ASSERT_TRUE(CurrentT->getTemplatedDecl());
-      EXPECT_EQ(CurrentT->getTemplatedDecl()->getPreviousDecl(),
-                PrevT->getTemplatedDecl());
-      return;
-    }
-
-    // Specializations.
-    if (auto *PrevF = dyn_cast<FunctionDecl>(Prev)) {
-      if (PrevF->getTemplatedKind() ==
-          FunctionDecl::TK_FunctionTemplateSpecialization) {
-        // There may be a hidden fwd spec decl before a spec decl.
-        // In that case the previous visible decl can be reached through that
-        // invisible one.
-        EXPECT_THAT(Prev, testing::AnyOf(
-                              Current->getPreviousDecl(),
-                              Current->getPreviousDecl()->getPreviousDecl()));
-        auto *ToTU = Prev->getTranslationUnitDecl();
-        auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
-            ToTU, functionTemplateDecl());
-        auto *FirstSpecD = *(TemplateD->spec_begin());
-        EXPECT_EQ(FirstSpecD->getCanonicalDecl(), PrevF->getCanonicalDecl());
-        return;
-      }
-    }
-
-    // The rest: Classes, Functions, etc.
-    EXPECT_EQ(Current->getPreviousDecl(), Prev);
-  }
-
-  void
-  TypedTest_PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition() {
-    Decl *FromTU = getTuDecl(getPrototype(), Lang_CXX);
-    auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    ASSERT_FALSE(FromD->isThisDeclarationADefinition());
-
-    Decl *ImportedD = Import(FromD, Lang_CXX);
-    Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
-    auto *ToD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(ImportedD == ToD);
-    EXPECT_FALSE(ToD->isThisDeclarationADefinition());
-    if (auto *ToT = dyn_cast<TemplateDecl>(ToD)) {
-      EXPECT_TRUE(ToT->getTemplatedDecl());
-    }
-  }
-
-  void TypedTest_DefinitionShouldBeImportedAsADefinition() {
-    Decl *FromTU = getTuDecl(getDefinition(), Lang_CXX);
-    auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    ASSERT_TRUE(FromD->isThisDeclarationADefinition());
-
-    Decl *ImportedD = Import(FromD, Lang_CXX);
-    Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
-    auto *ToD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(ToD->isThisDeclarationADefinition());
-    if (auto *ToT = dyn_cast<TemplateDecl>(ToD)) {
-      EXPECT_TRUE(ToT->getTemplatedDecl());
-    }
-  }
-
-  void TypedTest_ImportPrototypeAfterImportedPrototype() {
-    Decl *FromTU = getTuDecl(
-        getPrototype() + getPrototype(), Lang_CXX);
-    auto *From0 =
-        FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    auto *From1 = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    ASSERT_FALSE(From0->isThisDeclarationADefinition());
-    ASSERT_FALSE(From1->isThisDeclarationADefinition());
-
-    Decl *Imported0 = Import(From0, Lang_CXX);
-    Decl *Imported1 = Import(From1, Lang_CXX);
-    Decl *ToTU = Imported0->getTranslationUnitDecl();
-
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
-    auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    auto *To1 = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(Imported0 == To0);
-    EXPECT_TRUE(Imported1 == To1);
-    EXPECT_FALSE(To0->isThisDeclarationADefinition());
-    EXPECT_FALSE(To1->isThisDeclarationADefinition());
-
-    CheckPreviousDecl(To0, To1);
-  }
-
-  void TypedTest_ImportDefinitionAfterImportedPrototype() {
-    Decl *FromTU = getTuDecl(
-        getPrototype() + getDefinition(), Lang_CXX);
-    auto *FromProto = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    auto *FromDef = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
-    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
-
-    Decl *ImportedProto = Import(FromProto, Lang_CXX);
-    Decl *ImportedDef = Import(FromDef, Lang_CXX);
-    Decl *ToTU = ImportedProto->getTranslationUnitDecl();
-
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
-    auto *ToProto = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    auto *ToDef = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(ImportedProto == ToProto);
-    EXPECT_TRUE(ImportedDef == ToDef);
-    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
-    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
-
-    CheckPreviousDecl(ToProto, ToDef);
-  }
-
-  void TypedTest_ImportPrototypeAfterImportedDefinition() {
-    Decl *FromTU = getTuDecl(
-        getDefinition() + getPrototype(), Lang_CXX);
-    auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    auto *FromProto = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
-    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
-
-    Decl *ImportedDef = Import(FromDef, Lang_CXX);
-    Decl *ImportedProto = Import(FromProto, Lang_CXX);
-    Decl *ToTU = ImportedDef->getTranslationUnitDecl();
-
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
-    auto *ToDef = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    auto *ToProto = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(ImportedDef == ToDef);
-    EXPECT_TRUE(ImportedProto == ToProto);
-    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
-    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
-
-    CheckPreviousDecl(ToDef, ToProto);
-  }
-
-  void TypedTest_ImportPrototypes() {
-    Decl *FromTU0 = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
-    Decl *FromTU1 = getTuDecl(getPrototype(), Lang_CXX, "input1.cc");
-    auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU0, getPattern());
-    auto *From1 = FirstDeclMatcher<DeclTy>().match(FromTU1, getPattern());
-    ASSERT_FALSE(From0->isThisDeclarationADefinition());
-    ASSERT_FALSE(From1->isThisDeclarationADefinition());
-
-    Decl *Imported0 = Import(From0, Lang_CXX);
-    Decl *Imported1 = Import(From1, Lang_CXX);
-    Decl *ToTU = Imported0->getTranslationUnitDecl();
-
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
-    auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    auto *To1 = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(Imported0 == To0);
-    EXPECT_TRUE(Imported1 == To1);
-    EXPECT_FALSE(To0->isThisDeclarationADefinition());
-    EXPECT_FALSE(To1->isThisDeclarationADefinition());
-
-    CheckPreviousDecl(To0, To1);
-  }
-
-  void TypedTest_ImportDefinitions() {
-    Decl *FromTU0 = getTuDecl(getDefinition(), Lang_CXX, "input0.cc");
-    Decl *FromTU1 = getTuDecl(getDefinition(), Lang_CXX, "input1.cc");
-    auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU0, getPattern());
-    auto *From1 = FirstDeclMatcher<DeclTy>().match(FromTU1, getPattern());
-    ASSERT_TRUE(From0->isThisDeclarationADefinition());
-    ASSERT_TRUE(From1->isThisDeclarationADefinition());
-
-    Decl *Imported0 = Import(From0, Lang_CXX);
-    Decl *Imported1 = Import(From1, Lang_CXX);
-    Decl *ToTU = Imported0->getTranslationUnitDecl();
-
-    EXPECT_EQ(Imported0, Imported1);
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
-    auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(Imported0 == To0);
-    EXPECT_TRUE(To0->isThisDeclarationADefinition());
-    if (auto *ToT0 = dyn_cast<TemplateDecl>(To0)) {
-      EXPECT_TRUE(ToT0->getTemplatedDecl());
-    }
-  }
-
-  void TypedTest_ImportDefinitionThenPrototype() {
-    Decl *FromTUDef = getTuDecl(getDefinition(), Lang_CXX, "input0.cc");
-    Decl *FromTUProto = getTuDecl(getPrototype(), Lang_CXX, "input1.cc");
-    auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTUDef, getPattern());
-    auto *FromProto =
-        FirstDeclMatcher<DeclTy>().match(FromTUProto, getPattern());
-    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
-    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
-
-    Decl *ImportedDef = Import(FromDef, Lang_CXX);
-    Decl *ImportedProto = Import(FromProto, Lang_CXX);
-    Decl *ToTU = ImportedDef->getTranslationUnitDecl();
-
-    EXPECT_NE(ImportedDef, ImportedProto);
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
-    auto *ToDef = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    auto *ToProto = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(ImportedDef == ToDef);
-    EXPECT_TRUE(ImportedProto == ToProto);
-    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
-    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
-
-    CheckPreviousDecl(ToDef, ToProto);
-  }
-
-  void TypedTest_ImportPrototypeThenDefinition() {
-    Decl *FromTUProto = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
-    Decl *FromTUDef = getTuDecl(getDefinition(), Lang_CXX, "input1.cc");
-    auto *FromProto =
-        FirstDeclMatcher<DeclTy>().match(FromTUProto, getPattern());
-    auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTUDef, getPattern());
-    ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
-    ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
-
-    Decl *ImportedProto = Import(FromProto, Lang_CXX);
-    Decl *ImportedDef = Import(FromDef, Lang_CXX);
-    Decl *ToTU = ImportedDef->getTranslationUnitDecl();
-
-    EXPECT_NE(ImportedDef, ImportedProto);
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
-    auto *ToProto = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    auto *ToDef = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(ImportedDef == ToDef);
-    EXPECT_TRUE(ImportedProto == ToProto);
-    EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
-    EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
-
-    CheckPreviousDecl(ToProto, ToDef);
-  }
-
-  void TypedTest_WholeRedeclChainIsImportedAtOnce() {
-    Decl *FromTU = getTuDecl(getPrototype() + getDefinition(), Lang_CXX);
-    auto *FromD = // Definition
-        LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
-    ASSERT_TRUE(FromD->isThisDeclarationADefinition());
-
-    Decl *ImportedD = Import(FromD, Lang_CXX);
-    Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
-    // The whole redecl chain is imported at once.
-    EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
-    EXPECT_TRUE(cast<DeclTy>(ImportedD)->isThisDeclarationADefinition());
-  }
-
-  void TypedTest_ImportPrototypeThenProtoAndDefinition() {
-    {
-      Decl *FromTU = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
-      auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
-      Import(FromD, Lang_CXX);
-    }
-    {
-      Decl *FromTU =
-          getTuDecl(getPrototype() + getDefinition(), Lang_CXX, "input1.cc");
-      auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
-      Import(FromD, Lang_CXX);
-    }
-
-    Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
-
-    ASSERT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 3u);
-    DeclTy *ProtoD = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_FALSE(ProtoD->isThisDeclarationADefinition());
-
-    DeclTy *DefinitionD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
-    EXPECT_TRUE(DefinitionD->isThisDeclarationADefinition());
-
-    EXPECT_TRUE(DefinitionD->getPreviousDecl());
-    EXPECT_FALSE(
-        DefinitionD->getPreviousDecl()->isThisDeclarationADefinition());
-
-    CheckPreviousDecl(ProtoD, DefinitionD->getPreviousDecl());
-  }
-};
-
-#define ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(BaseTemplate, TypeParam,       \
-                                                NamePrefix, TestCase)          \
-  using BaseTemplate##TypeParam = BaseTemplate<TypeParam>;                     \
-  TEST_P(BaseTemplate##TypeParam, NamePrefix##TestCase) {                      \
-    TypedTest_##TestCase();                                                    \
-  }
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, Function, ,
-    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, Class, ,
-    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, Variable, ,
-    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, FunctionTemplate, ,
-    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, ClassTemplate, ,
-    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, FunctionTemplateSpec, ,
-    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, ClassTemplateSpec, ,
-    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, Function, , DefinitionShouldBeImportedAsADefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, Class, , DefinitionShouldBeImportedAsADefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, Variable, , DefinitionShouldBeImportedAsADefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, FunctionTemplate, ,
-    DefinitionShouldBeImportedAsADefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, ClassTemplate, , DefinitionShouldBeImportedAsADefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, FunctionTemplateSpec, ,
-    DefinitionShouldBeImportedAsADefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
-    RedeclChain, ClassTemplateSpec, , DefinitionShouldBeImportedAsADefinition)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportPrototypeAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
-                                        ImportPrototypeAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportPrototypeAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportPrototypeAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
-                                        ImportPrototypeAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportPrototypeAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
-                                        ImportPrototypeAfterImportedPrototype)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportDefinitionAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
-                                        ImportDefinitionAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportDefinitionAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportDefinitionAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
-                                        ImportDefinitionAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportDefinitionAfterImportedPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
-                                        ImportDefinitionAfterImportedPrototype)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportPrototypeAfterImportedDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
-                                        ImportPrototypeAfterImportedDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportPrototypeAfterImportedDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportPrototypeAfterImportedDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
-                                        ImportPrototypeAfterImportedDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportPrototypeAfterImportedDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
-                                        ImportPrototypeAfterImportedDefinition)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportPrototypes)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportPrototypes)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportPrototypes)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportPrototypes)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
-                                        ImportPrototypes)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
-                                        ImportPrototypes)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportPrototypes)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportDefinitions)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
-                                        ImportDefinitions)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportDefinitions)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportDefinitions)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
-                                        ImportDefinitions)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
-                                        ImportDefinitions)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportDefinitions)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportDefinitionThenPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
-                                        ImportDefinitionThenPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportDefinitionThenPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportDefinitionThenPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
-                                        ImportDefinitionThenPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportDefinitionThenPrototype)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
-                                        ImportDefinitionThenPrototype)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportPrototypeThenDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
-                                        ImportPrototypeThenDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportPrototypeThenDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportPrototypeThenDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
-                                        ImportPrototypeThenDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportPrototypeThenDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
-                                        ImportPrototypeThenDefinition)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        WholeRedeclChainIsImportedAtOnce)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        WholeRedeclChainIsImportedAtOnce)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        WholeRedeclChainIsImportedAtOnce)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        WholeRedeclChainIsImportedAtOnce)
-
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
-                                        ImportPrototypeThenProtoAndDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
-                                        ImportPrototypeThenProtoAndDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
-                                        ImportPrototypeThenProtoAndDefinition)
-ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
-                                        ImportPrototypeThenProtoAndDefinition)
-
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunction,
-                        DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClass,
-                        DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainVariable,
-                        DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplate,
-                        DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplate,
-                        DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplateSpec,
-                        DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplateSpec,
-                        DefaultTestValuesForRunOptions, );
-
-
 
 struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
 

Added: cfe/trunk/unittests/AST/ASTImporterVisibilityTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterVisibilityTest.cpp?rev=360572&view=auto
==============================================================================
--- cfe/trunk/unittests/AST/ASTImporterVisibilityTest.cpp (added)
+++ cfe/trunk/unittests/AST/ASTImporterVisibilityTest.cpp Mon May 13 03:06:25 2019
@@ -0,0 +1,219 @@
+//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Type-parameterized tests for the correct import of Decls with different
+// visibility.
+//
+//===----------------------------------------------------------------------===//
+
+// Define this to have ::testing::Combine available.
+// FIXME: Better solution for this?
+#define GTEST_HAS_COMBINE 1
+
+#include "ASTImporterFixtures.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using internal::BindableMatcher;
+
+// Type parameters for type-parameterized test fixtures.
+struct GetFunPattern {
+  using DeclTy = FunctionDecl;
+  BindableMatcher<Decl> operator()() { return functionDecl(hasName("f")); }
+};
+struct GetVarPattern {
+  using DeclTy = VarDecl;
+  BindableMatcher<Decl> operator()() { return varDecl(hasName("v")); }
+};
+
+// Values for the value-parameterized test fixtures.
+// FunctionDecl:
+const auto *ExternF = "void f();";
+const auto *StaticF = "static void f();";
+const auto *AnonF = "namespace { void f(); }";
+// VarDecl:
+const auto *ExternV = "extern int v;";
+const auto *StaticV = "static int v;";
+const auto *AnonV = "namespace { extern int v; }";
+
+// First value in tuple: Compile options.
+// Second value in tuple: Source code to be used in the test.
+using ImportVisibilityChainParams =
+    ::testing::WithParamInterface<std::tuple<ArgVector, const char *>>;
+// Fixture to test the redecl chain of Decls with the same visibility. Gtest
+// makes it possible to have either value-parameterized or type-parameterized
+// fixtures. However, we cannot have both value- and type-parameterized test
+// fixtures. This is a value-parameterized test fixture in the gtest sense. We
+// intend to mimic gtest's type-parameters via the PatternFactory template
+// parameter. We manually instantiate the different tests with the each types.
+template <typename PatternFactory>
+class ImportVisibilityChain
+    : public ASTImporterTestBase, public ImportVisibilityChainParams {
+protected:
+  using DeclTy = typename PatternFactory::DeclTy;
+  ArgVector getExtraArgs() const override { return std::get<0>(GetParam()); }
+  std::string getCode() const { return std::get<1>(GetParam()); }
+  BindableMatcher<Decl> getPattern() const { return PatternFactory()(); }
+
+  // Type-parameterized test.
+  void TypedTest_ImportChain() {
+    std::string Code = getCode() + getCode();
+    auto Pattern = getPattern();
+
+    TranslationUnitDecl *FromTu = getTuDecl(Code, Lang_CXX, "input0.cc");
+
+    auto *FromD0 = FirstDeclMatcher<DeclTy>().match(FromTu, Pattern);
+    auto *FromD1 = LastDeclMatcher<DeclTy>().match(FromTu, Pattern);
+
+    auto *ToD0 = Import(FromD0, Lang_CXX);
+    auto *ToD1 = Import(FromD1, Lang_CXX);
+
+    EXPECT_TRUE(ToD0);
+    ASSERT_TRUE(ToD1);
+    EXPECT_NE(ToD0, ToD1);
+    EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
+  }
+};
+
+// Manual instantiation of the fixture with each type.
+using ImportFunctionsVisibilityChain = ImportVisibilityChain<GetFunPattern>;
+using ImportVariablesVisibilityChain = ImportVisibilityChain<GetVarPattern>;
+// Value-parameterized test for the first type.
+TEST_P(ImportFunctionsVisibilityChain, ImportChain) {
+  TypedTest_ImportChain();
+}
+// Value-parameterized test for the second type.
+TEST_P(ImportVariablesVisibilityChain, ImportChain) {
+  TypedTest_ImportChain();
+}
+
+// Automatic instantiation of the value-parameterized tests.
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctionsVisibilityChain,
+                        ::testing::Combine(
+                           DefaultTestValuesForRunOptions,
+                           ::testing::Values(ExternF, StaticF, AnonF)), );
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportVariablesVisibilityChain,
+    ::testing::Combine(
+        DefaultTestValuesForRunOptions,
+        // There is no point to instantiate with StaticV, because in C++ we can
+        // forward declare a variable only with the 'extern' keyword.
+        // Consequently, each fwd declared variable has external linkage.  This
+        // is different in the C language where any declaration without an
+        // initializer is a tentative definition, subsequent definitions may be
+        // provided but they must have the same linkage.  See also the test
+        // ImportVariableChainInC which test for this special C Lang case.
+        ::testing::Values(ExternV, AnonV)), );
+
+// First value in tuple: Compile options.
+// Second value in tuple: Tuple with informations for the test.
+// Code for first import (or initial code), code to import, whether the `f`
+// functions are expected to be linked in a declaration chain.
+// One value of this tuple is combined with every value of compile options.
+// The test can have a single tuple as parameter only.
+using ImportVisibilityParams = ::testing::WithParamInterface<
+    std::tuple<ArgVector, std::tuple<const char *, const char *, bool>>>;
+
+template <typename PatternFactory>
+class ImportVisibility
+    : public ASTImporterTestBase,
+      public ImportVisibilityParams {
+protected:
+  using DeclTy = typename PatternFactory::DeclTy;
+  ArgVector getExtraArgs() const override { return std::get<0>(GetParam()); }
+  std::string getCode0() const { return std::get<0>(std::get<1>(GetParam())); }
+  std::string getCode1() const { return std::get<1>(std::get<1>(GetParam())); }
+  bool shouldBeLinked() const { return std::get<2>(std::get<1>(GetParam())); }
+  BindableMatcher<Decl> getPattern() const { return PatternFactory()(); }
+
+  void TypedTest_ImportAfter() {
+    TranslationUnitDecl *ToTu = getToTuDecl(getCode0(), Lang_CXX);
+    TranslationUnitDecl *FromTu = getTuDecl(getCode1(), Lang_CXX, "input1.cc");
+
+    auto *ToD0 = FirstDeclMatcher<DeclTy>().match(ToTu, getPattern());
+    auto *FromD1 = FirstDeclMatcher<DeclTy>().match(FromTu, getPattern());
+
+    auto *ToD1 = Import(FromD1, Lang_CXX);
+
+    ASSERT_TRUE(ToD0);
+    ASSERT_TRUE(ToD1);
+    EXPECT_NE(ToD0, ToD1);
+
+    if (shouldBeLinked())
+      EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
+    else
+      EXPECT_FALSE(ToD1->getPreviousDecl());
+  }
+
+  void TypedTest_ImportAfterImport() {
+    TranslationUnitDecl *FromTu0 = getTuDecl(getCode0(), Lang_CXX, "input0.cc");
+    TranslationUnitDecl *FromTu1 = getTuDecl(getCode1(), Lang_CXX, "input1.cc");
+    auto *FromD0 = FirstDeclMatcher<DeclTy>().match(FromTu0, getPattern());
+    auto *FromD1 = FirstDeclMatcher<DeclTy>().match(FromTu1, getPattern());
+    auto *ToD0 = Import(FromD0, Lang_CXX);
+    auto *ToD1 = Import(FromD1, Lang_CXX);
+    ASSERT_TRUE(ToD0);
+    ASSERT_TRUE(ToD1);
+    EXPECT_NE(ToD0, ToD1);
+    if (shouldBeLinked())
+      EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
+    else
+      EXPECT_FALSE(ToD1->getPreviousDecl());
+  }
+};
+using ImportFunctionsVisibility = ImportVisibility<GetFunPattern>;
+using ImportVariablesVisibility = ImportVisibility<GetVarPattern>;
+
+// FunctionDecl.
+TEST_P(ImportFunctionsVisibility, ImportAfter) {
+  TypedTest_ImportAfter();
+}
+TEST_P(ImportFunctionsVisibility, ImportAfterImport) {
+  TypedTest_ImportAfterImport();
+}
+// VarDecl.
+TEST_P(ImportVariablesVisibility, ImportAfter) {
+  TypedTest_ImportAfter();
+}
+TEST_P(ImportVariablesVisibility, ImportAfterImport) {
+  TypedTest_ImportAfterImport();
+}
+
+const bool ExpectLink = true;
+const bool ExpectNotLink = false;
+
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportFunctionsVisibility,
+    ::testing::Combine(
+        DefaultTestValuesForRunOptions,
+        ::testing::Values(std::make_tuple(ExternF, ExternF, ExpectLink),
+                          std::make_tuple(ExternF, StaticF, ExpectNotLink),
+                          std::make_tuple(ExternF, AnonF, ExpectNotLink),
+                          std::make_tuple(StaticF, ExternF, ExpectNotLink),
+                          std::make_tuple(StaticF, StaticF, ExpectNotLink),
+                          std::make_tuple(StaticF, AnonF, ExpectNotLink),
+                          std::make_tuple(AnonF, ExternF, ExpectNotLink),
+                          std::make_tuple(AnonF, StaticF, ExpectNotLink),
+                          std::make_tuple(AnonF, AnonF, ExpectNotLink))), );
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportVariablesVisibility,
+    ::testing::Combine(
+        DefaultTestValuesForRunOptions,
+        ::testing::Values(std::make_tuple(ExternV, ExternV, ExpectLink),
+                          std::make_tuple(ExternV, StaticV, ExpectNotLink),
+                          std::make_tuple(ExternV, AnonV, ExpectNotLink),
+                          std::make_tuple(StaticV, ExternV, ExpectNotLink),
+                          std::make_tuple(StaticV, StaticV, ExpectNotLink),
+                          std::make_tuple(StaticV, AnonV, ExpectNotLink),
+                          std::make_tuple(AnonV, ExternV, ExpectNotLink),
+                          std::make_tuple(AnonV, StaticV, ExpectNotLink),
+                          std::make_tuple(AnonV, AnonV, ExpectNotLink))), );
+
+} // end namespace ast_matchers
+} // end namespace clang

Modified: cfe/trunk/unittests/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=360572&r1=360571&r2=360572&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/CMakeLists.txt (original)
+++ cfe/trunk/unittests/AST/CMakeLists.txt Mon May 13 03:06:25 2019
@@ -8,7 +8,10 @@ endif()
 
 add_clang_unittest(ASTTests
   ASTContextParentMapTest.cpp
+  ASTImporterFixtures.cpp
   ASTImporterTest.cpp
+  ASTImporterGenericRedeclTest.cpp
+  ASTImporterVisibilityTest.cpp
   ASTTypeTraitsTest.cpp
   ASTVectorTest.cpp
   CommentLexer.cpp




More information about the cfe-commits mailing list