[ASTImporter] Fix redecl chain of classes and class templates

Summary:
The crux of the issue that is being fixed is that lookup could not find
previous decls of a friend class. The solution involves making the
friend declarations visible in their decl context (i.e. adding them to
the lookup table).
Also, we simplify `VisitRecordDecl` greatly.

This fix involves two other repairs (without these the unittests fail):
(1) We could not handle the addition of injected class types properly
when a redecl chain was involved, now this is fixed.
(2) DeclContext::removeDecl failed if the lookup table in Vector form
did not contain the to be removed element. This caused troubles in
ASTImporter::ImportDeclContext. This is also fixed.

Reviewers: a_sidorin, balazske, a.sidorin

Subscribers: rnkovacs, dkrupp, Szelethus, cfe-commits

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

llvm-svn: 349349
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 0450cb4..3407f7d 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -11,9 +11,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/ASTImporter.h"
 #include "MatchVerifier.h"
 #include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTImporter.h"
+#include "clang/AST/DeclContextInternals.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Tooling/Tooling.h"
@@ -1808,6 +1809,65 @@
   EXPECT_NE(To0->getCanonicalDecl(), To1->getCanonicalDecl());
 }
 
+TEST_P(ASTImporterTestBase, AnonymousRecords) {
+  auto *Code =
+      R"(
+      struct X {
+        struct { int a; };
+        struct { int b; };
+      };
+      )";
+  Decl *FromTU0 = getTuDecl(Code, Lang_C, "input0.c");
+
+  Decl *FromTU1 = getTuDecl(Code, Lang_C, "input1.c");
+
+  auto *X0 =
+      FirstDeclMatcher<RecordDecl>().match(FromTU0, recordDecl(hasName("X")));
+  auto *X1 =
+      FirstDeclMatcher<RecordDecl>().match(FromTU1, recordDecl(hasName("X")));
+  Import(X0, Lang_C);
+  Import(X1, Lang_C);
+
+  auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  // We expect no (ODR) warning during the import.
+  EXPECT_EQ(0u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
+  EXPECT_EQ(1u,
+            DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
+}
+
+TEST_P(ASTImporterTestBase, AnonymousRecordsReversed) {
+  Decl *FromTU0 = getTuDecl(
+      R"(
+      struct X {
+        struct { int a; };
+        struct { int b; };
+      };
+      )",
+      Lang_C, "input0.c");
+
+  Decl *FromTU1 = getTuDecl(
+      R"(
+      struct X { // reversed order
+        struct { int b; };
+        struct { int a; };
+      };
+      )",
+      Lang_C, "input1.c");
+
+  auto *X0 =
+      FirstDeclMatcher<RecordDecl>().match(FromTU0, recordDecl(hasName("X")));
+  auto *X1 =
+      FirstDeclMatcher<RecordDecl>().match(FromTU1, recordDecl(hasName("X")));
+  Import(X0, Lang_C);
+  Import(X1, Lang_C);
+
+  auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  // We expect one (ODR) warning during the import.
+  EXPECT_EQ(1u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
+  EXPECT_EQ(2u,
+            DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
+}
+
 TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag) {
   auto Pattern = varDecl(hasName("x"));
   VarDecl *Imported1;
@@ -2930,93 +2990,6 @@
   EXPECT_EQ(FromIndex, 3u);
 }
 
-TEST_P(
-    ASTImporterTestBase,
-    ImportOfFriendRecordDoesNotMergeDefinition) {
-  Decl *FromTU = getTuDecl(
-      R"(
-      class A {
-        template <int I> class F {};
-        class X {
-          template <int I> friend class F;
-        };
-      };
-      )",
-      Lang_CXX, "input0.cc");
-
-  auto *FromClass = FirstDeclMatcher<CXXRecordDecl>().match(
-      FromTU, cxxRecordDecl(hasName("F"), isDefinition()));
-  auto *FromFriendClass = LastDeclMatcher<CXXRecordDecl>().match(
-      FromTU, cxxRecordDecl(hasName("F")));
-
-  ASSERT_TRUE(FromClass);
-  ASSERT_TRUE(FromFriendClass);
-  ASSERT_NE(FromClass, FromFriendClass);
-  ASSERT_EQ(FromFriendClass->getDefinition(), FromClass);
-  ASSERT_EQ(FromFriendClass->getPreviousDecl(), FromClass);
-  ASSERT_EQ(
-      FromFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
-      FromClass->getDescribedClassTemplate());
-
-  auto *ToClass = cast<CXXRecordDecl>(Import(FromClass, Lang_CXX));
-  auto *ToFriendClass = cast<CXXRecordDecl>(Import(FromFriendClass, Lang_CXX));
-
-  EXPECT_TRUE(ToClass);
-  EXPECT_TRUE(ToFriendClass);
-  EXPECT_NE(ToClass, ToFriendClass);
-  EXPECT_EQ(ToFriendClass->getDefinition(), ToClass);
-  EXPECT_EQ(ToFriendClass->getPreviousDecl(), ToClass);
-  EXPECT_EQ(
-      ToFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
-      ToClass->getDescribedClassTemplate());
-}
-
-TEST_P(
-    ASTImporterTestBase,
-    ImportOfRecursiveFriendClass) {
-  Decl *FromTu = getTuDecl(
-      R"(
-      class declToImport {
-        friend class declToImport;
-      };
-      )",
-      Lang_CXX, "input.cc");
-
-  auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
-      FromTu, cxxRecordDecl(hasName("declToImport")));
-  auto *ToD = Import(FromD, Lang_CXX);
-  auto Pattern = cxxRecordDecl(hasName("declToImport"), has(friendDecl()));
-  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
-}
-
-TEST_P(
-    ASTImporterTestBase,
-    ImportOfRecursiveFriendClassTemplate) {
-  Decl *FromTu = getTuDecl(
-      R"(
-      template <class A> class declToImport {
-        template <class A1> friend class declToImport;
-      };
-      )",
-      Lang_CXX, "input.cc");
-
-  auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
-      FromTu, classTemplateDecl(hasName("declToImport")));
-  auto *ToD = Import(FromD, Lang_CXX);
-
-  auto Pattern = classTemplateDecl(
-      has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()))))));
-  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
-
-  auto *Class =
-      FirstDeclMatcher<ClassTemplateDecl>().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher<FriendDecl>().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
-}
-
 TEST_P(ASTImporterTestBase, MergeFieldDeclsOfClassTemplateSpecialization) {
   std::string ClassTemplate =
       R"(
@@ -3381,6 +3354,542 @@
   EXPECT_TRUE(ImportedD->getDefinition());
 }
 
+struct ImportClasses : ASTImporterTestBase {};
+
+TEST_P(ImportClasses,
+       PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) {
+  Decl *FromTU = getTuDecl("class X;", Lang_CXX);
+  auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  auto FromD = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
+
+  Decl *ImportedD = Import(FromD, Lang_CXX);
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 1u);
+  auto ToD = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == ToD);
+  EXPECT_FALSE(ToD->isThisDeclarationADefinition());
+}
+
+TEST_P(ImportClasses, ImportPrototypeAfterImportedPrototype) {
+  Decl *FromTU = getTuDecl("class X; class X;", Lang_CXX);
+  auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  auto From0 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
+  auto From1 = LastDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
+
+  Decl *Imported0 = Import(From0, Lang_CXX);
+  Decl *Imported1 = Import(From1, Lang_CXX);
+  Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(Imported0 == To0);
+  EXPECT_TRUE(Imported1 == To1);
+  EXPECT_FALSE(To0->isThisDeclarationADefinition());
+  EXPECT_FALSE(To1->isThisDeclarationADefinition());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
+TEST_P(ImportClasses, DefinitionShouldBeImportedAsADefinition) {
+  Decl *FromTU = getTuDecl("class X {};", Lang_CXX);
+  auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
+
+  Decl *ImportedD = Import(FromD, Lang_CXX);
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 1u);
+  EXPECT_TRUE(cast<CXXRecordDecl>(ImportedD)->isThisDeclarationADefinition());
+}
+
+TEST_P(ImportClasses, ImportPrototypeFromDifferentTUAfterImportedPrototype) {
+  Decl *FromTU0 = getTuDecl("class X;", Lang_CXX, "input0.cc");
+  Decl *FromTU1 = getTuDecl("class X;", Lang_CXX, "input1.cc");
+  auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  auto From0 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
+  auto From1 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
+
+  Decl *Imported0 = Import(From0, Lang_CXX);
+  Decl *Imported1 = Import(From1, Lang_CXX);
+  Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(Imported0 == To0);
+  EXPECT_TRUE(Imported1 == To1);
+  EXPECT_FALSE(To0->isThisDeclarationADefinition());
+  EXPECT_FALSE(To1->isThisDeclarationADefinition());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
+TEST_P(ImportClasses, ImportDefinitions) {
+  Decl *FromTU0 = getTuDecl("class X {};", Lang_CXX, "input0.cc");
+  Decl *FromTU1 = getTuDecl("class X {};", Lang_CXX, "input1.cc");
+  auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  auto From0 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
+  auto From1 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
+
+  Decl *Imported0 = Import(From0, Lang_CXX);
+  Decl *Imported1 = Import(From1, Lang_CXX);
+  Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+  EXPECT_EQ(Imported0, Imported1);
+  EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 1u);
+  auto To0 = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(Imported0 == To0);
+  EXPECT_TRUE(To0->isThisDeclarationADefinition());
+}
+
+TEST_P(ImportClasses, ImportDefinitionThenPrototype) {
+  Decl *FromTU0 = getTuDecl("class X {};", Lang_CXX, "input0.cc");
+  Decl *FromTU1 = getTuDecl("class X;", Lang_CXX, "input1.cc");
+  auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  auto FromDef = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
+  auto FromProto = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
+
+  Decl *ImportedDef = Import(FromDef, Lang_CXX);
+  Decl *ImportedProto = Import(FromProto, Lang_CXX);
+  Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+  EXPECT_NE(ImportedDef, ImportedProto);
+  EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
+  auto ToDef = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  auto ToProto = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedDef == ToDef);
+  EXPECT_TRUE(ImportedProto == ToProto);
+  EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+  EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+  EXPECT_EQ(ToProto->getPreviousDecl(), ToDef);
+}
+
+TEST_P(ImportClasses, ImportPrototypeThenDefinition) {
+  Decl *FromTU0 = getTuDecl("class X;", Lang_CXX, "input0.cc");
+  Decl *FromTU1 = getTuDecl("class X {};", Lang_CXX, "input1.cc");
+  auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
+  auto FromProto = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
+  auto FromDef = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
+
+  Decl *ImportedProto = Import(FromProto, Lang_CXX);
+  Decl *ImportedDef = Import(FromDef, Lang_CXX);
+  Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+  EXPECT_NE(ImportedDef, ImportedProto);
+  EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
+  auto ToProto = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  auto ToDef = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedDef == ToDef);
+  EXPECT_TRUE(ImportedProto == ToProto);
+  EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+  EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+  EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
+}
+
+struct ImportClassTemplates : ASTImporterTestBase {};
+
+TEST_P(ImportClassTemplates,
+       PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) {
+  Decl *FromTU = getTuDecl("template <class T> class X;", Lang_CXX);
+  auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
+  auto FromD = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
+
+  Decl *ImportedD = Import(FromD, Lang_CXX);
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 1u);
+  auto ToD = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == ToD);
+  ASSERT_TRUE(ToD->getTemplatedDecl());
+  EXPECT_FALSE(ToD->isThisDeclarationADefinition());
+}
+
+TEST_P(ImportClassTemplates, ImportPrototypeAfterImportedPrototype) {
+  Decl *FromTU = getTuDecl(
+      "template <class T> class X; template <class T> class X;", Lang_CXX);
+  auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
+  auto From0 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
+  auto From1 = LastDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
+
+  Decl *Imported0 = Import(From0, Lang_CXX);
+  Decl *Imported1 = Import(From1, Lang_CXX);
+  Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(Imported0 == To0);
+  EXPECT_TRUE(Imported1 == To1);
+  ASSERT_TRUE(To0->getTemplatedDecl());
+  ASSERT_TRUE(To1->getTemplatedDecl());
+  EXPECT_FALSE(To0->isThisDeclarationADefinition());
+  EXPECT_FALSE(To1->isThisDeclarationADefinition());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+  EXPECT_EQ(To1->getTemplatedDecl()->getPreviousDecl(),
+            To0->getTemplatedDecl());
+}
+
+TEST_P(ImportClassTemplates, DefinitionShouldBeImportedAsADefinition) {
+  Decl *FromTU = getTuDecl("template <class T> class X {};", Lang_CXX);
+  auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
+  auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
+
+  Decl *ImportedD = Import(FromD, Lang_CXX);
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 1u);
+  auto ToD = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  ASSERT_TRUE(ToD->getTemplatedDecl());
+  EXPECT_TRUE(ToD->isThisDeclarationADefinition());
+}
+
+TEST_P(ImportClassTemplates,
+       ImportPrototypeFromDifferentTUAfterImportedPrototype) {
+  Decl *FromTU0 =
+      getTuDecl("template <class T> class X;", Lang_CXX, "input0.cc");
+  Decl *FromTU1 =
+      getTuDecl("template <class T> class X;", Lang_CXX, "input1.cc");
+  auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
+  auto From0 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
+  auto From1 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
+
+  Decl *Imported0 = Import(From0, Lang_CXX);
+  Decl *Imported1 = Import(From1, Lang_CXX);
+  Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(Imported0 == To0);
+  EXPECT_TRUE(Imported1 == To1);
+  ASSERT_TRUE(To0->getTemplatedDecl());
+  ASSERT_TRUE(To1->getTemplatedDecl());
+  EXPECT_FALSE(To0->isThisDeclarationADefinition());
+  EXPECT_FALSE(To1->isThisDeclarationADefinition());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+  EXPECT_EQ(To1->getTemplatedDecl()->getPreviousDecl(),
+            To0->getTemplatedDecl());
+}
+
+TEST_P(ImportClassTemplates, ImportDefinitions) {
+  Decl *FromTU0 =
+      getTuDecl("template <class T> class X {};", Lang_CXX, "input0.cc");
+  Decl *FromTU1 =
+      getTuDecl("template <class T> class X {};", Lang_CXX, "input1.cc");
+  auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
+  auto From0 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
+  auto From1 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
+
+  Decl *Imported0 = Import(From0, Lang_CXX);
+  Decl *Imported1 = Import(From1, Lang_CXX);
+  Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+  EXPECT_EQ(Imported0, Imported1);
+  EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 1u);
+  auto To0 = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(Imported0 == To0);
+  ASSERT_TRUE(To0->getTemplatedDecl());
+  EXPECT_TRUE(To0->isThisDeclarationADefinition());
+}
+
+TEST_P(ImportClassTemplates, ImportDefinitionThenPrototype) {
+  Decl *FromTU0 =
+      getTuDecl("template <class T> class X {};", Lang_CXX, "input0.cc");
+  Decl *FromTU1 =
+      getTuDecl("template <class T> class X;", Lang_CXX, "input1.cc");
+  auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
+  auto FromDef = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
+  auto FromProto =
+      FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
+
+  Decl *ImportedDef = Import(FromDef, Lang_CXX);
+  Decl *ImportedProto = Import(FromProto, Lang_CXX);
+  Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+  EXPECT_NE(ImportedDef, ImportedProto);
+  EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
+  auto ToDef = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  auto ToProto = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedDef == ToDef);
+  EXPECT_TRUE(ImportedProto == ToProto);
+  ASSERT_TRUE(ToDef->getTemplatedDecl());
+  ASSERT_TRUE(ToProto->getTemplatedDecl());
+  EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+  EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+  EXPECT_EQ(ToProto->getPreviousDecl(), ToDef);
+  EXPECT_EQ(ToProto->getTemplatedDecl()->getPreviousDecl(),
+            ToDef->getTemplatedDecl());
+}
+
+TEST_P(ImportClassTemplates, ImportPrototypeThenDefinition) {
+  Decl *FromTU0 =
+      getTuDecl("template <class T> class X;", Lang_CXX, "input0.cc");
+  Decl *FromTU1 =
+      getTuDecl("template <class T> class X {};", Lang_CXX, "input1.cc");
+  auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
+  auto FromProto =
+      FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
+  auto FromDef = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
+
+  Decl *ImportedProto = Import(FromProto, Lang_CXX);
+  Decl *ImportedDef = Import(FromDef, Lang_CXX);
+  Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+  EXPECT_NE(ImportedDef, ImportedProto);
+  EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
+  auto ToProto = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  auto ToDef = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedDef == ToDef);
+  EXPECT_TRUE(ImportedProto == ToProto);
+  ASSERT_TRUE(ToProto->getTemplatedDecl());
+  ASSERT_TRUE(ToDef->getTemplatedDecl());
+  EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+  EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+  EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
+  EXPECT_EQ(ToDef->getTemplatedDecl()->getPreviousDecl(),
+            ToProto->getTemplatedDecl());
+}
+
+struct ImportFriendClasses : ASTImporterTestBase {};
+
+TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
+  Decl *FromTU = getTuDecl(
+      R"(
+      class A {
+        template <int I> class F {};
+        class X {
+          template <int I> friend class F;
+        };
+      };
+      )",
+      Lang_CXX, "input0.cc");
+
+  auto *FromClass = FirstDeclMatcher<CXXRecordDecl>().match(
+      FromTU, cxxRecordDecl(hasName("F"), isDefinition()));
+  auto *FromFriendClass = LastDeclMatcher<CXXRecordDecl>().match(
+      FromTU, cxxRecordDecl(hasName("F")));
+
+  ASSERT_TRUE(FromClass);
+  ASSERT_TRUE(FromFriendClass);
+  ASSERT_NE(FromClass, FromFriendClass);
+  ASSERT_EQ(FromFriendClass->getDefinition(), FromClass);
+  ASSERT_EQ(FromFriendClass->getPreviousDecl(), FromClass);
+  ASSERT_EQ(FromFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
+            FromClass->getDescribedClassTemplate());
+
+  auto *ToClass = cast<CXXRecordDecl>(Import(FromClass, Lang_CXX));
+  auto *ToFriendClass = cast<CXXRecordDecl>(Import(FromFriendClass, Lang_CXX));
+
+  EXPECT_TRUE(ToClass);
+  EXPECT_TRUE(ToFriendClass);
+  EXPECT_NE(ToClass, ToFriendClass);
+  EXPECT_EQ(ToFriendClass->getDefinition(), ToClass);
+  EXPECT_EQ(ToFriendClass->getPreviousDecl(), ToClass);
+  EXPECT_EQ(ToFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
+            ToClass->getDescribedClassTemplate());
+}
+
+TEST_P(ImportFriendClasses, ImportOfRecursiveFriendClass) {
+  Decl *FromTu = getTuDecl(
+      R"(
+      class declToImport {
+        friend class declToImport;
+      };
+      )",
+      Lang_CXX, "input.cc");
+
+  auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
+      FromTu, cxxRecordDecl(hasName("declToImport")));
+  auto *ToD = Import(FromD, Lang_CXX);
+  auto Pattern = cxxRecordDecl(has(friendDecl()));
+  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
+  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
+}
+
+TEST_P(ImportFriendClasses, ImportOfRecursiveFriendClassTemplate) {
+  Decl *FromTu = getTuDecl(
+      R"(
+      template<class A> class declToImport {
+        template<class A1> friend class declToImport;
+      };
+      )",
+      Lang_CXX, "input.cc");
+
+  auto *FromD =
+      FirstDeclMatcher<ClassTemplateDecl>().match(FromTu, classTemplateDecl());
+  auto *ToD = Import(FromD, Lang_CXX);
+
+  auto Pattern = classTemplateDecl(
+      has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()))))));
+  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
+  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
+
+  auto *Class =
+      FirstDeclMatcher<ClassTemplateDecl>().match(ToD, classTemplateDecl());
+  auto *Friend = FirstDeclMatcher<FriendDecl>().match(ToD, friendDecl());
+  EXPECT_NE(Friend->getFriendDecl(), Class);
+  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+}
+
+TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
+  auto Pattern = classTemplateSpecializationDecl(hasName("X"));
+
+  ClassTemplateSpecializationDecl *Imported1;
+  {
+    Decl *FromTU = getTuDecl("template<class T> class X;"
+                             "struct Y { friend class X<int>; };",
+                             Lang_CXX, "input0.cc");
+    auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
+        FromTU, Pattern);
+
+    Imported1 = cast<ClassTemplateSpecializationDecl>(Import(FromD, Lang_CXX));
+  }
+  ClassTemplateSpecializationDecl *Imported2;
+  {
+    Decl *FromTU = getTuDecl("template<class T> class X;"
+                             "template<> class X<int>{};"
+                             "struct Z { friend class X<int>; };",
+                             Lang_CXX, "input1.cc");
+    auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
+        FromTU, Pattern);
+
+    Imported2 = cast<ClassTemplateSpecializationDecl>(Import(FromD, Lang_CXX));
+  }
+
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  EXPECT_EQ(DeclCounter<ClassTemplateSpecializationDecl>().match(ToTU, Pattern),
+            2u);
+  ASSERT_TRUE(Imported2->getPreviousDecl());
+  EXPECT_EQ(Imported2->getPreviousDecl(), Imported1);
+}
+
+TEST_P(ImportFriendClasses, TypeForDeclShouldBeSetInTemplated) {
+  Decl *FromTU0 = getTuDecl(
+      R"(
+      class X {
+        class Y;
+      };
+      class X::Y {
+        template <typename T>
+        friend class F; // The decl context of F is the global namespace.
+      };
+      )",
+      Lang_CXX, "input0.cc");
+  auto *Fwd = FirstDeclMatcher<ClassTemplateDecl>().match(
+      FromTU0, classTemplateDecl(hasName("F")));
+  auto *Imported0 = cast<ClassTemplateDecl>(Import(Fwd, Lang_CXX));
+  Decl *FromTU1 = getTuDecl(
+      R"(
+      template <typename T>
+      class F {};
+      )",
+      Lang_CXX, "input1.cc");
+  auto *Definition = FirstDeclMatcher<ClassTemplateDecl>().match(
+      FromTU1, classTemplateDecl(hasName("F")));
+  auto *Imported1 = cast<ClassTemplateDecl>(Import(Definition, Lang_CXX));
+  EXPECT_EQ(Imported0->getTemplatedDecl()->getTypeForDecl(),
+            Imported1->getTemplatedDecl()->getTypeForDecl());
+}
+
+TEST_P(ImportFriendClasses, DeclsFromFriendsShouldBeInRedeclChains) {
+  Decl *From, *To;
+  std::tie(From, To) =
+      getImportedDecl("class declToImport {};", Lang_CXX,
+                      "class Y { friend class declToImport; };", Lang_CXX);
+  auto *Imported = cast<CXXRecordDecl>(To);
+
+  EXPECT_TRUE(Imported->getPreviousDecl());
+}
+
+TEST_P(ImportFriendClasses,
+       ImportOfClassTemplateDefinitionShouldConnectToFwdFriend) {
+  Decl *ToTU = getToTuDecl(
+      R"(
+      class X {
+        class Y;
+      };
+      class X::Y {
+        template <typename T>
+        friend class F; // The decl context of F is the global namespace.
+      };
+      )",
+      Lang_CXX);
+  auto *ToDecl = FirstDeclMatcher<ClassTemplateDecl>().match(
+      ToTU, classTemplateDecl(hasName("F")));
+  Decl *FromTU = getTuDecl(
+      R"(
+      template <typename T>
+      class F {};
+      )",
+      Lang_CXX, "input0.cc");
+  auto *Definition = FirstDeclMatcher<ClassTemplateDecl>().match(
+      FromTU, classTemplateDecl(hasName("F")));
+  auto *ImportedDef = cast<ClassTemplateDecl>(Import(Definition, Lang_CXX));
+  EXPECT_TRUE(ImportedDef->getPreviousDecl());
+  EXPECT_EQ(ToDecl, ImportedDef->getPreviousDecl());
+  EXPECT_EQ(ToDecl->getTemplatedDecl(),
+            ImportedDef->getTemplatedDecl()->getPreviousDecl());
+}
+
+TEST_P(ImportFriendClasses,
+       ImportOfClassTemplateDefinitionAndFwdFriendShouldBeLinked) {
+  Decl *FromTU0 = getTuDecl(
+      R"(
+      class X {
+        class Y;
+      };
+      class X::Y {
+        template <typename T>
+        friend class F; // The decl context of F is the global namespace.
+      };
+      )",
+      Lang_CXX, "input0.cc");
+  auto *Fwd = FirstDeclMatcher<ClassTemplateDecl>().match(
+      FromTU0, classTemplateDecl(hasName("F")));
+  auto *ImportedFwd = cast<ClassTemplateDecl>(Import(Fwd, Lang_CXX));
+  Decl *FromTU1 = getTuDecl(
+      R"(
+      template <typename T>
+      class F {};
+      )",
+      Lang_CXX, "input1.cc");
+  auto *Definition = FirstDeclMatcher<ClassTemplateDecl>().match(
+      FromTU1, classTemplateDecl(hasName("F")));
+  auto *ImportedDef = cast<ClassTemplateDecl>(Import(Definition, Lang_CXX));
+  EXPECT_TRUE(ImportedDef->getPreviousDecl());
+  EXPECT_EQ(ImportedFwd, ImportedDef->getPreviousDecl());
+  EXPECT_EQ(ImportedFwd->getTemplatedDecl(),
+            ImportedDef->getTemplatedDecl()->getPreviousDecl());
+}
+
+TEST_P(ImportFriendClasses, ImportOfClassDefinitionAndFwdFriendShouldBeLinked) {
+  Decl *FromTU0 = getTuDecl(
+      R"(
+      class X {
+        class Y;
+      };
+      class X::Y {
+        friend class F; // The decl context of F is the global namespace.
+      };
+      )",
+      Lang_CXX, "input0.cc");
+  auto *Friend = FirstDeclMatcher<FriendDecl>().match(FromTU0, friendDecl());
+  QualType FT = Friend->getFriendType()->getType();
+  FT = FromTU0->getASTContext().getCanonicalType(FT);
+  auto *Fwd = cast<TagType>(FT)->getDecl();
+  auto *ImportedFwd = Import(Fwd, Lang_CXX);
+  Decl *FromTU1 = getTuDecl(
+      R"(
+      class F {};
+      )",
+      Lang_CXX, "input1.cc");
+  auto *Definition = FirstDeclMatcher<CXXRecordDecl>().match(
+      FromTU1, cxxRecordDecl(hasName("F")));
+  auto *ImportedDef = Import(Definition, Lang_CXX);
+  EXPECT_TRUE(ImportedDef->getPreviousDecl());
+  EXPECT_EQ(ImportedFwd, ImportedDef->getPreviousDecl());
+}
+
 struct DeclContextTest : ASTImporterTestBase {};
 
 TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
@@ -3410,6 +3919,40 @@
   EXPECT_FALSE(NS->containsDecl(Spec));
 }
 
+TEST_P(DeclContextTest,
+       removeDeclShouldNotFailEvenIfWeHaveExternalVisibleStorage) {
+  Decl *TU = getTuDecl("extern int A; int A;", Lang_CXX);
+  auto *A0 = FirstDeclMatcher<VarDecl>().match(TU, varDecl(hasName("A")));
+  auto *A1 = LastDeclMatcher<VarDecl>().match(TU, varDecl(hasName("A")));
+
+  // Investigate the list.
+  auto *DC = A0->getDeclContext();
+  ASSERT_TRUE(DC->containsDecl(A0));
+  ASSERT_TRUE(DC->containsDecl(A1));
+
+  // Investigate the lookup table.
+  auto *Map = DC->getLookupPtr();
+  ASSERT_TRUE(Map);
+  auto I = Map->find(A0->getDeclName());
+  ASSERT_NE(I, Map->end());
+  StoredDeclsList &L = I->second;
+  // The lookup table contains the most recent decl of A.
+  ASSERT_NE(L.getAsDecl(), A0);
+  ASSERT_EQ(L.getAsDecl(), A1);
+
+  ASSERT_TRUE(L.getAsDecl());
+  // Simulate the private function DeclContext::reconcileExternalVisibleStorage.
+  // The point here is to have a Vec with only one element, which is not the
+  // one we are going to delete from the DC later.
+  L.setHasExternalDecls();
+  ASSERT_TRUE(L.getAsVector());
+  ASSERT_EQ(1u, L.getAsVector()->size());
+
+  // This asserts in the old implementation.
+  DC->removeDecl(A0);
+  EXPECT_FALSE(DC->containsDecl(A0));
+}
+
 struct ImportFunctionTemplateSpecializations : ASTImporterTestBase {};
 
 TEST_P(ImportFunctionTemplateSpecializations,
@@ -3827,6 +4370,15 @@
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctions,
                         DefaultTestValuesForRunOptions, );
 
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClasses,
+                        DefaultTestValuesForRunOptions, );
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClassTemplates,
+                        DefaultTestValuesForRunOptions, );
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendClasses,
+                        DefaultTestValuesForRunOptions, );
+
 INSTANTIATE_TEST_CASE_P(ParameterizedTests,
                         ImportFunctionTemplateSpecializations,
                         DefaultTestValuesForRunOptions, );