summaryrefslogtreecommitdiffstats
path: root/unittests/AST/ASTImporterTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/AST/ASTImporterTest.cpp')
-rw-r--r--unittests/AST/ASTImporterTest.cpp2287
1 files changed, 1522 insertions, 765 deletions
diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp
index c6acf573e5..7cac2b5703 100644
--- a/unittests/AST/ASTImporterTest.cpp
+++ b/unittests/AST/ASTImporterTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -11,6 +10,10 @@
//
//===----------------------------------------------------------------------===//
+// Define this to have ::testing::Combine available.
+// FIXME: Better solution for this?
+#define GTEST_HAS_COMBINE 1
+
#include "clang/AST/ASTImporter.h"
#include "MatchVerifier.h"
#include "clang/AST/ASTContext.h"
@@ -41,7 +44,7 @@ createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
assert(ToAST);
ASTContext &ToCtx = ToAST->getASTContext();
auto *OFS = static_cast<llvm::vfs::OverlayFileSystem *>(
- ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
+ &ToCtx.getSourceManager().getFileManager().getVirtualFileSystem());
auto *MFS = static_cast<llvm::vfs::InMemoryFileSystem *>(
OFS->overlays_begin()->get());
MFS->addFile(FileName, 0, std::move(Buffer));
@@ -59,27 +62,35 @@ 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.
-struct ParameterizedTestsFixture : ::testing::TestWithParam<ArgVector> {
+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 = GetParam();
+ 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 ParameterizedTestsFixture {
+class TestImportBase : public CompilerOptionSpecificTest,
+ public ::testing::WithParamInterface<ArgVector> {
template <typename NodeType>
- NodeType importNode(ASTUnit *From, ASTUnit *To, ASTImporter &Importer,
- NodeType Node) {
+ llvm::Expected<NodeType> importNode(ASTUnit *From, ASTUnit *To,
+ ASTImporter &Importer, NodeType Node) {
ASTContext &ToCtx = To->getASTContext();
// Add 'From' file to virtual file system so importer can 'find' it
@@ -89,17 +100,19 @@ class TestImportBase : public ParameterizedTestsFixture {
createVirtualFileIfNeeded(To, FromFileName,
From->getBufferForFile(FromFileName));
- auto Imported = Importer.Import(Node);
+ auto Imported = Importer.Import_New(Node);
- // This should dump source locations and assert if some source locations
- // were not imported.
- SmallString<1024> ImportChecker;
- llvm::raw_svector_ostream ToNothing(ImportChecker);
- ToCtx.getTranslationUnitDecl()->print(ToNothing);
+ if (Imported) {
+ // This should dump source locations and assert if some source locations
+ // were not imported.
+ SmallString<1024> ImportChecker;
+ llvm::raw_svector_ostream ToNothing(ImportChecker);
+ ToCtx.getTranslationUnitDecl()->print(ToNothing);
- // This traverses the AST to catch certain bugs like poorly or not
- // implemented subtrees.
- Imported->dump(ToNothing);
+ // This traverses the AST to catch certain bugs like poorly or not
+ // implemented subtrees.
+ (*Imported)->dump(ToNothing);
+ }
return Imported;
}
@@ -140,11 +153,16 @@ class TestImportBase : public ParameterizedTestsFixture {
EXPECT_TRUE(Verifier.match(ToImport, WrapperMatcher));
auto Imported = importNode(FromAST.get(), ToAST.get(), Importer, ToImport);
- if (!Imported)
- return testing::AssertionFailure() << "Import failed, nullptr returned!";
-
+ if (!Imported) {
+ std::string ErrorText;
+ handleAllErrors(
+ Imported.takeError(),
+ [&ErrorText](const ImportError &Err) { ErrorText = Err.message(); });
+ return testing::AssertionFailure()
+ << "Import failed, error: \"" << ErrorText << "\"!";
+ }
- return Verifier.match(Imported, WrapperMatcher);
+ return Verifier.match(*Imported, WrapperMatcher);
}
template <typename NodeType>
@@ -160,6 +178,9 @@ class TestImportBase : public ParameterizedTestsFixture {
VerificationMatcher);
}
+protected:
+ ArgVector getExtraArgs() const override { return GetParam(); }
+
public:
/// Test how AST node named "declToImport" located in the translation unit
@@ -263,7 +284,9 @@ public:
EXPECT_TRUE(FoundDecl.size() == 1);
const Decl *ToImport = selectFirst<Decl>(DeclToImportID, FoundDecl);
auto Imported = importNode(From, To, *ImporterRef, ToImport);
- EXPECT_TRUE(Imported);
+ EXPECT_TRUE(static_cast<bool>(Imported));
+ if (!Imported)
+ llvm::consumeError(Imported.takeError());
}
// Find the declaration and import it.
@@ -285,11 +308,22 @@ template <typename T> RecordDecl *getRecordDecl(T *D) {
// 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 ParameterizedTestsFixture {
+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;
@@ -302,22 +336,32 @@ class ASTImporterTestBase : public ParameterizedTestsFixture {
std::unique_ptr<ASTUnit> Unit;
TranslationUnitDecl *TUDecl = nullptr;
std::unique_ptr<ASTImporter> Importer;
- TU(StringRef Code, StringRef FileName, ArgVector Args)
+ 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()) {
+ 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(
- new ASTImporter(ToAST->getASTContext(), ToAST->getFileManager(),
- Unit->getASTContext(), Unit->getFileManager(),
- false, &LookupTable));
- }
+ if (!Importer)
+ Importer.reset(Creator(ToAST->getASTContext(), ToAST->getFileManager(),
+ Unit->getASTContext(), Unit->getFileManager(),
+ false, &LookupTable));
assert(&ToAST->getASTContext() == &Importer->getToContext());
createVirtualFileIfNeeded(ToAST, FileName, Code);
}
@@ -325,13 +369,23 @@ class ASTImporterTestBase : public ParameterizedTestsFixture {
Decl *import(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST,
Decl *FromDecl) {
lazyInitImporter(LookupTable, ToAST);
- return Importer->Import(FromDecl);
+ 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);
- return Importer->Import(FromType);
+ if (auto ImportedOrErr = Importer->Import_New(FromType))
+ return *ImportedOrErr;
+ else {
+ llvm::consumeError(ImportedOrErr.takeError());
+ return QualType{};
+ }
}
};
@@ -367,7 +421,7 @@ class ASTImporterTestBase : public ParameterizedTestsFixture {
// 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 = std::find_if(FromTUs.begin(), FromTUs.end(), [From](const TU &E) {
+ auto It = llvm::find_if(FromTUs, [From](const TU &E) {
return E.TUDecl == From->getTranslationUnitDecl();
});
assert(It != FromTUs.end());
@@ -391,7 +445,7 @@ public:
ArgVector FromArgs = getArgVectorForLanguage(FromLang),
ToArgs = getArgVectorForLanguage(ToLang);
- FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs);
+ FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs, Creator);
TU &FromTU = FromTUs.back();
assert(!ToAST);
@@ -421,10 +475,9 @@ public:
// name).
TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
StringRef FileName = "input.cc") {
- assert(
- std::find_if(FromTUs.begin(), FromTUs.end(), [FileName](const TU &E) {
- return E.FileName == FileName;
- }) == FromTUs.end());
+ 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);
@@ -451,6 +504,10 @@ public:
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);
@@ -474,11 +531,18 @@ public:
}
};
+class ASTImporterOptionSpecificTestBase
+ : public ASTImporterTestBase,
+ public ::testing::WithParamInterface<ArgVector> {
+protected:
+ ArgVector getExtraArgs() const override { return GetParam(); }
+};
+
struct ImportExpr : TestImportBase {};
struct ImportType : TestImportBase {};
struct ImportDecl : TestImportBase {};
-struct CanonicalRedeclChain : ASTImporterTestBase {};
+struct CanonicalRedeclChain : ASTImporterOptionSpecificTestBase {};
TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers) {
Decl *FromTU = getTuDecl("void f();", Lang_CXX);
@@ -519,6 +583,74 @@ TEST_P(CanonicalRedeclChain, ShouldBeSameForAllDeclInTheChain) {
EXPECT_THAT(RedeclsD1, ::testing::ContainerEq(RedeclsD2));
}
+namespace {
+struct RedirectingImporter : public ASTImporter {
+ using ASTImporter::ASTImporter;
+
+protected:
+ llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {
+ auto *ND = dyn_cast<NamedDecl>(FromD);
+ if (!ND || ND->getName() != "shouldNotBeImported")
+ return ASTImporter::ImportImpl(FromD);
+ for (Decl *D : getToContext().getTranslationUnitDecl()->decls()) {
+ if (auto *ND = dyn_cast<NamedDecl>(D))
+ if (ND->getName() == "realDecl") {
+ RegisterImportedDecl(FromD, ND);
+ return ND;
+ }
+ }
+ return ASTImporter::ImportImpl(FromD);
+ }
+};
+
+} // namespace
+
+struct RedirectingImporterTest : ASTImporterOptionSpecificTestBase {
+ RedirectingImporterTest() {
+ Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ bool MinimalImport, ASTImporterLookupTable *LookupTable) {
+ return new RedirectingImporter(ToContext, ToFileManager, FromContext,
+ FromFileManager, MinimalImport,
+ LookupTable);
+ };
+ }
+};
+
+// Test that an ASTImporter subclass can intercept an import call.
+TEST_P(RedirectingImporterTest, InterceptImport) {
+ Decl *From, *To;
+ std::tie(From, To) =
+ getImportedDecl("class shouldNotBeImported {};", Lang_CXX,
+ "class realDecl {};", Lang_CXX, "shouldNotBeImported");
+ auto *Imported = cast<CXXRecordDecl>(To);
+ EXPECT_EQ(Imported->getQualifiedNameAsString(), "realDecl");
+
+ // Make sure our importer prevented the importing of the decl.
+ auto *ToTU = Imported->getTranslationUnitDecl();
+ auto Pattern = functionDecl(hasName("shouldNotBeImported"));
+ unsigned count =
+ DeclCounterWithPredicate<CXXRecordDecl>().match(ToTU, Pattern);
+ EXPECT_EQ(0U, count);
+}
+
+// Test that when we indirectly import a declaration the custom ASTImporter
+// is still intercepting the import.
+TEST_P(RedirectingImporterTest, InterceptIndirectImport) {
+ Decl *From, *To;
+ std::tie(From, To) =
+ getImportedDecl("class shouldNotBeImported {};"
+ "class F { shouldNotBeImported f; };",
+ Lang_CXX, "class realDecl {};", Lang_CXX, "F");
+
+ // Make sure our ASTImporter prevented the importing of the decl.
+ auto *ToTU = To->getTranslationUnitDecl();
+ auto Pattern = functionDecl(hasName("shouldNotBeImported"));
+ unsigned count =
+ DeclCounterWithPredicate<CXXRecordDecl>().match(ToTU, Pattern);
+ EXPECT_EQ(0U, count);
+}
+
TEST_P(ImportExpr, ImportStringLiteral) {
MatchVerifier<Decl> Verifier;
testImport(
@@ -538,6 +670,17 @@ TEST_P(ImportExpr, ImportStringLiteral) {
stringLiteral(hasType(asString("const char [7]"))))));
}
+TEST_P(ImportExpr, ImportChooseExpr) {
+ MatchVerifier<Decl> Verifier;
+
+ // This case tests C code that is not condition-dependent and has a true
+ // condition.
+ testImport(
+ "void declToImport() { (void)__builtin_choose_expr(1, 2, 3); }",
+ Lang_C, "", Lang_C, Verifier,
+ functionDecl(hasDescendant(chooseExpr())));
+}
+
TEST_P(ImportExpr, ImportGNUNullExpr) {
MatchVerifier<Decl> Verifier;
testImport(
@@ -1001,7 +1144,7 @@ TEST_P(ImportDecl, ImportRecordDeclInFunc) {
has(declStmt(hasSingleDecl(varDecl(hasName("d")))))))));
}
-TEST_P(ASTImporterTestBase, ImportRecordTypeInFunc) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordTypeInFunc) {
Decl *FromTU = getTuDecl("int declToImport() { "
" struct data_t {int a;int b;};"
" struct data_t d;"
@@ -1016,7 +1159,7 @@ TEST_P(ASTImporterTestBase, ImportRecordTypeInFunc) {
EXPECT_FALSE(ToType.isNull());
}
-TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncParams) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncParams) {
// This construct is not supported by ASTImporter.
Decl *FromTU = getTuDecl(
"int declToImport(struct data_t{int a;int b;} ***d){ return 0; }",
@@ -1028,7 +1171,7 @@ TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncParams) {
EXPECT_EQ(To, nullptr);
}
-TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncFromMacro) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncFromMacro) {
Decl *FromTU = getTuDecl(
"#define NONAME_SIZEOF(type) sizeof(struct{type *dummy;}) \n"
"int declToImport(){ return NONAME_SIZEOF(int); }",
@@ -1043,7 +1186,8 @@ TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncFromMacro) {
hasDescendant(unaryExprOrTypeTraitExpr()))));
}
-TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncParamsFromMacro) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportRecordDeclInFuncParamsFromMacro) {
// This construct is not supported by ASTImporter.
Decl *FromTU = getTuDecl(
"#define PAIR_STRUCT(type) struct data_t{type a;type b;} \n"
@@ -1195,7 +1339,28 @@ TEST_P(ImportExpr, DependentSizedArrayType) {
has(fieldDecl(hasType(dependentSizedArrayType())))))));
}
-TEST_P(ASTImporterTestBase, ImportOfTemplatedDeclOfClassTemplateDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportBeginLocOfDeclRefExpr) {
+ Decl *FromTU = getTuDecl(
+ "class A { public: static int X; }; void f() { (void)A::X; }", Lang_CXX);
+ auto From = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ ASSERT_TRUE(From);
+ ASSERT_TRUE(
+ cast<CStyleCastExpr>(cast<CompoundStmt>(From->getBody())->body_front())
+ ->getSubExpr()
+ ->getBeginLoc()
+ .isValid());
+ FunctionDecl *To = Import(From, Lang_CXX);
+ ASSERT_TRUE(To);
+ ASSERT_TRUE(
+ cast<CStyleCastExpr>(cast<CompoundStmt>(To->getBody())->body_front())
+ ->getSubExpr()
+ ->getBeginLoc()
+ .isValid());
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportOfTemplatedDeclOfClassTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> struct S{};", Lang_CXX);
auto From =
FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, classTemplateDecl());
@@ -1208,7 +1373,8 @@ TEST_P(ASTImporterTestBase, ImportOfTemplatedDeclOfClassTemplateDecl) {
EXPECT_EQ(ToTemplated1, ToTemplated);
}
-TEST_P(ASTImporterTestBase, ImportOfTemplatedDeclOfFunctionTemplateDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportOfTemplatedDeclOfFunctionTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> void f(){}", Lang_CXX);
auto From = FirstDeclMatcher<FunctionTemplateDecl>().match(
FromTU, functionTemplateDecl());
@@ -1221,7 +1387,7 @@ TEST_P(ASTImporterTestBase, ImportOfTemplatedDeclOfFunctionTemplateDecl) {
EXPECT_EQ(ToTemplated1, ToTemplated);
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportOfTemplatedDeclShouldImportTheClassTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> struct S{};", Lang_CXX);
auto FromFT =
@@ -1237,7 +1403,7 @@ TEST_P(ASTImporterTestBase,
EXPECT_TRUE(ToFT);
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportOfTemplatedDeclShouldImportTheFunctionTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> void f(){}", Lang_CXX);
auto FromFT = FirstDeclMatcher<FunctionTemplateDecl>().match(
@@ -1253,7 +1419,7 @@ TEST_P(ASTImporterTestBase,
EXPECT_TRUE(ToFT);
}
-TEST_P(ASTImporterTestBase, ImportCorrectTemplatedDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplatedDecl) {
auto Code =
R"(
namespace x {
@@ -1284,7 +1450,31 @@ TEST_P(ASTImporterTestBase, ImportCorrectTemplatedDecl) {
ASSERT_EQ(ToTemplated1, ToTemplated);
}
-TEST_P(ASTImporterTestBase, ImportFunctionWithBackReferringParameter) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportChooseExpr) {
+ // This tests the import of isConditionTrue directly to make sure the importer
+ // gets it right.
+ Decl *From, *To;
+ std::tie(From, To) = getImportedDecl(
+ "void declToImport() { (void)__builtin_choose_expr(1, 0, 1); }",
+ Lang_C, "", Lang_C);
+
+ auto ToResults = match(chooseExpr().bind("choose"), To->getASTContext());
+ auto FromResults = match(chooseExpr().bind("choose"), From->getASTContext());
+
+ const ChooseExpr *FromChooseExpr =
+ selectFirst<ChooseExpr>("choose", FromResults);
+ ASSERT_TRUE(FromChooseExpr);
+
+ const ChooseExpr *ToChooseExpr = selectFirst<ChooseExpr>("choose", ToResults);
+ ASSERT_TRUE(ToChooseExpr);
+
+ EXPECT_EQ(FromChooseExpr->isConditionTrue(), ToChooseExpr->isConditionTrue());
+ EXPECT_EQ(FromChooseExpr->isConditionDependent(),
+ ToChooseExpr->isConditionDependent());
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportFunctionWithBackReferringParameter) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1311,7 +1501,7 @@ TEST_P(ASTImporterTestBase, ImportFunctionWithBackReferringParameter) {
EXPECT_TRUE(Verifier.match(To, Matcher));
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
TUshouldNotContainTemplatedDeclOfFunctionTemplates) {
Decl *From, *To;
std::tie(From, To) =
@@ -1337,7 +1527,8 @@ TEST_P(ASTImporterTestBase,
EXPECT_TRUE(Check(To));
}
-TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfClassTemplates) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ TUshouldNotContainTemplatedDeclOfClassTemplates) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl("template <typename T> struct declToImport { T t; };"
@@ -1362,7 +1553,8 @@ TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfClassTemplates) {
EXPECT_TRUE(Check(To));
}
-TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfTypeAlias) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ TUshouldNotContainTemplatedDeclOfTypeAlias) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl(
@@ -1389,9 +1581,8 @@ TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfTypeAlias) {
EXPECT_TRUE(Check(To));
}
-TEST_P(
- ASTImporterTestBase,
- TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1432,7 +1623,7 @@ AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector<StringRef>, Order) {
return Index == Order.size();
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
TUshouldContainClassTemplateSpecializationOfExplicitInstantiation) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1459,7 +1650,8 @@ TEST_P(ASTImporterTestBase,
EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
}
-TEST_P(ASTImporterTestBase, CXXRecordDeclFieldsShouldBeInCorrectOrder) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ CXXRecordDeclFieldsShouldBeInCorrectOrder) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl(
@@ -1471,7 +1663,7 @@ TEST_P(ASTImporterTestBase, CXXRecordDeclFieldsShouldBeInCorrectOrder) {
EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
DISABLED_CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1493,7 +1685,7 @@ TEST_P(ASTImporterTestBase,
Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
}
-TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase, ShouldImportImplicitCXXRecordDecl) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1509,7 +1701,8 @@ TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDecl) {
EXPECT_TRUE(Verifier.match(To, Matcher));
}
-TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDeclOfClassTemplate) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ShouldImportImplicitCXXRecordDeclOfClassTemplate) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1526,9 +1719,8 @@ TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDeclOfClassTemplate) {
EXPECT_TRUE(Verifier.match(To, Matcher));
}
-TEST_P(
- ASTImporterTestBase,
- ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1548,7 +1740,7 @@ TEST_P(
MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
}
-TEST_P(ASTImporterTestBase, IDNSOrdinary) {
+TEST_P(ASTImporterOptionSpecificTestBase, IDNSOrdinary) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl("void declToImport() {}", Lang_CXX, "", Lang_CXX);
@@ -1560,7 +1752,7 @@ TEST_P(ASTImporterTestBase, IDNSOrdinary) {
EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
}
-TEST_P(ASTImporterTestBase, IDNSOfNonmemberOperator) {
+TEST_P(ASTImporterOptionSpecificTestBase, IDNSOfNonmemberOperator) {
Decl *FromTU = getTuDecl(
R"(
struct X {};
@@ -1572,7 +1764,7 @@ TEST_P(ASTImporterTestBase, IDNSOfNonmemberOperator) {
EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ShouldImportMembersOfClassTemplateSpecializationDecl) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1592,7 +1784,8 @@ TEST_P(ASTImporterTestBase,
MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
}
-TEST_P(ASTImporterTestBase, ImportDefinitionOfClassTemplateAfterFwdDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportDefinitionOfClassTemplateAfterFwdDecl) {
{
Decl *FromTU = getTuDecl(
R"(
@@ -1625,7 +1818,7 @@ TEST_P(ASTImporterTestBase, ImportDefinitionOfClassTemplateAfterFwdDecl) {
}
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportDefinitionOfClassTemplateIfThereIsAnExistingFwdDeclAndDefinition) {
Decl *ToTU = getToTuDecl(
R"(
@@ -1665,7 +1858,7 @@ TEST_P(ASTImporterTestBase,
.match(ToTU, classTemplateDecl()));
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportDefinitionOfClassIfThereIsAnExistingFwdDeclAndDefinition) {
Decl *ToTU = getToTuDecl(
R"(
@@ -1708,7 +1901,7 @@ static void CompareSourceRanges(SourceRange Range1, SourceRange Range2,
CompareSourceLocs(FullSourceLoc{ Range1.getEnd(), SM1 },
FullSourceLoc{ Range2.getEnd(), SM2 });
}
-TEST_P(ASTImporterTestBase, ImportSourceLocs) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportSourceLocs) {
Decl *FromTU = getTuDecl(
R"(
#define MFOO(arg) arg = arg + 1
@@ -1738,7 +1931,7 @@ TEST_P(ASTImporterTestBase, ImportSourceLocs) {
FromSM);
}
-TEST_P(ASTImporterTestBase, ImportNestedMacro) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportNestedMacro) {
Decl *FromTU = getTuDecl(
R"(
#define FUNC_INT void declToImport
@@ -1756,9 +1949,8 @@ TEST_P(ASTImporterTestBase, ImportNestedMacro) {
}
TEST_P(
- ASTImporterTestBase,
- ImportDefinitionOfClassTemplateSpecIfThereIsAnExistingFwdDeclAndDefinition)
-{
+ ASTImporterOptionSpecificTestBase,
+ ImportDefinitionOfClassTemplateSpecIfThereIsAnExistingFwdDeclAndDefinition) {
Decl *ToTU = getToTuDecl(
R"(
template <typename T>
@@ -1800,7 +1992,7 @@ TEST_P(
.match(ToTU, classTemplateSpecializationDecl()));
}
-TEST_P(ASTImporterTestBase, ObjectsWithUnnamedStructType) {
+TEST_P(ASTImporterOptionSpecificTestBase, ObjectsWithUnnamedStructType) {
Decl *FromTU = getTuDecl(
R"(
struct { int a; int b; } object0 = { 2, 3 };
@@ -1824,7 +2016,7 @@ TEST_P(ASTImporterTestBase, ObjectsWithUnnamedStructType) {
EXPECT_NE(To0->getCanonicalDecl(), To1->getCanonicalDecl());
}
-TEST_P(ASTImporterTestBase, AnonymousRecords) {
+TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecords) {
auto *Code =
R"(
struct X {
@@ -1850,7 +2042,7 @@ TEST_P(ASTImporterTestBase, AnonymousRecords) {
DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
}
-TEST_P(ASTImporterTestBase, AnonymousRecordsReversed) {
+TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecordsReversed) {
Decl *FromTU0 = getTuDecl(
R"(
struct X {
@@ -1883,7 +2075,7 @@ TEST_P(ASTImporterTestBase, AnonymousRecordsReversed) {
DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
}
-TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag) {
auto Pattern = varDecl(hasName("x"));
VarDecl *Imported1;
{
@@ -1909,7 +2101,7 @@ TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag) {
EXPECT_TRUE(Imported2->isUsed(false));
}
-TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag2) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag2) {
auto Pattern = varDecl(hasName("x"));
VarDecl *ExistingD;
{
@@ -1927,7 +2119,7 @@ TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag2) {
EXPECT_TRUE(ExistingD->isUsed(false));
}
-TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag3) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag3) {
auto Pattern = varDecl(hasName("a"));
VarDecl *ExistingD;
{
@@ -1958,7 +2150,7 @@ TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag3) {
EXPECT_TRUE(ExistingD->isUsed(false));
}
-TEST_P(ASTImporterTestBase, ReimportWithUsedFlag) {
+TEST_P(ASTImporterOptionSpecificTestBase, ReimportWithUsedFlag) {
auto Pattern = varDecl(hasName("x"));
Decl *FromTU = getTuDecl("int x;", Lang_CXX, "input0.cc");
@@ -1975,34 +2167,7 @@ TEST_P(ASTImporterTestBase, ReimportWithUsedFlag) {
EXPECT_TRUE(Imported2->isUsed(false));
}
-struct ImportFunctions : ASTImporterTestBase {};
-
-TEST_P(ImportFunctions,
- DefinitionShouldBeImportedAsDefintionWhenThereIsAPrototype) {
- Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
- auto Pattern = functionDecl(hasName("f"));
- FunctionDecl *FromD = // Definition
- LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
-}
-
-TEST_P(ImportFunctions, DefinitionShouldBeImportedAsADefinition) {
- Decl *FromTU = getTuDecl("void f() {}", Lang_CXX);
- auto Pattern = functionDecl(hasName("f"));
- FunctionDecl *FromD =
- FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
- EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
-}
+struct ImportFunctions : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportFunctions, ImportPrototypeOfRecursiveFunction) {
Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
@@ -2040,138 +2205,6 @@ TEST_P(ImportFunctions, ImportDefinitionOfRecursiveFunction) {
EXPECT_EQ(To1->getPreviousDecl(), To0);
}
-TEST_P(ImportFunctions, ImportPrototypes) {
- auto Pattern = functionDecl(hasName("f"));
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctions, ImportDefinitions) {
- auto Pattern = functionDecl(hasName("f"));
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f(){};", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
-}
-
-TEST_P(ImportFunctions, ImportDefinitionThenPrototype) {
- auto Pattern = functionDecl(hasName("f"));
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctions, ImportPrototypeThenDefinition) {
- auto Pattern = functionDecl(hasName("f"));
-
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
- FunctionDecl *FromD =
- FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input1.cc");
- FunctionDecl *FromD =
- FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
- ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_FALSE(ProtoD->doesThisDeclarationHaveABody());
- FunctionDecl *DefinitionD =
- LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
- EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
-}
-
-TEST_P(ImportFunctions, ImportPrototypeThenProtoAndDefinition) {
- auto Pattern = functionDecl(hasName("f"));
-
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f(); void f(){}", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
-
- ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 3u);
- FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_FALSE(ProtoD->doesThisDeclarationHaveABody());
-
- FunctionDecl *DefinitionD =
- LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
-
- EXPECT_TRUE(DefinitionD->getPreviousDecl());
- EXPECT_FALSE(DefinitionD->getPreviousDecl()->doesThisDeclarationHaveABody());
- EXPECT_EQ(DefinitionD->getPreviousDecl()->getPreviousDecl(), ProtoD);
-}
-
TEST_P(ImportFunctions, OverriddenMethodsShouldBeImported) {
auto Code =
R"(
@@ -2233,6 +2266,521 @@ TEST_P(ImportFunctions,
}).match(ToTU, functionDecl()));
}
+TEST_P(ImportFunctions, ImportOverriddenMethodTwice) {
+ auto Code =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ )";
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto DFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
+
+ Decl *FromTU0 = getTuDecl(Code, Lang_CXX);
+ auto *DF = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP);
+ Import(DF, Lang_CXX);
+
+ Decl *FromTU1 = getTuDecl(Code, Lang_CXX, "input1.cc");
+ auto *BF = FirstDeclMatcher<CXXMethodDecl>().match(FromTU1, BFP);
+ Import(BF, Lang_CXX);
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
+}
+
+TEST_P(ImportFunctions, ImportOverriddenMethodTwiceDefinitionFirst) {
+ auto CodeWithoutDef =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ )";
+ auto CodeWithDef =
+ R"(
+ struct B { virtual void f(){}; };
+ struct D:B { void f(){}; };
+ )";
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto DFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
+ auto BFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition());
+ auto DFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("D"))), isDefinition());
+ auto FDefAllP = cxxMethodDecl(hasName("f"), isDefinition());
+
+ {
+ Decl *FromTU = getTuDecl(CodeWithDef, Lang_CXX, "input0.cc");
+ auto *FromD = FirstDeclMatcher<CXXMethodDecl>().match(FromTU, DFP);
+ Import(FromD, Lang_CXX);
+ }
+ {
+ Decl *FromTU = getTuDecl(CodeWithoutDef, Lang_CXX, "input1.cc");
+ auto *FromB = FirstDeclMatcher<CXXMethodDecl>().match(FromTU, BFP);
+ Import(FromB, Lang_CXX);
+ }
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FDefAllP), 2u);
+}
+
+TEST_P(ImportFunctions, ImportOverriddenMethodTwiceOutOfClassDef) {
+ auto Code =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ void B::f(){};
+ )";
+
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto BFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition());
+ auto DFP = cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))),
+ unless(isDefinition()));
+
+ Decl *FromTU0 = getTuDecl(Code, Lang_CXX);
+ auto *D = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP);
+ Import(D, Lang_CXX);
+
+ Decl *FromTU1 = getTuDecl(Code, Lang_CXX, "input1.cc");
+ auto *B = FirstDeclMatcher<CXXMethodDecl>().match(FromTU1, BFP);
+ Import(B, Lang_CXX);
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u);
+
+ auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("B")));
+ auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP);
+ auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match(
+ ToTU, cxxMethodDecl(hasName("f"), isDefinition()));
+
+ // The definition should be out-of-class.
+ EXPECT_NE(ToBFInClass, ToBFOutOfClass);
+ EXPECT_NE(ToBFInClass->getLexicalDeclContext(),
+ ToBFOutOfClass->getLexicalDeclContext());
+ EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB);
+ EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU);
+
+ // Check that the redecl chain is intact.
+ EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass);
+}
+
+TEST_P(ImportFunctions,
+ ImportOverriddenMethodTwiceOutOfClassDefInSeparateCode) {
+ auto CodeTU0 =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ )";
+ auto CodeTU1 =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ void B::f(){}
+ void D::f(){}
+ void foo(B &b, D &d) { b.f(); d.f(); }
+ )";
+
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto BFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition());
+ auto DFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
+ auto DFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("D"))), isDefinition());
+ auto FooDef = functionDecl(hasName("foo"));
+
+ {
+ Decl *FromTU0 = getTuDecl(CodeTU0, Lang_CXX, "input0.cc");
+ auto *D = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP);
+ Import(D, Lang_CXX);
+ }
+
+ {
+ Decl *FromTU1 = getTuDecl(CodeTU1, Lang_CXX, "input1.cc");
+ auto *Foo = FirstDeclMatcher<FunctionDecl>().match(FromTU1, FooDef);
+ Import(Foo, Lang_CXX);
+ }
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 0u);
+
+ auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("B")));
+ auto *ToD = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("D")));
+ auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP);
+ auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match(
+ ToTU, cxxMethodDecl(hasName("f"), isDefinition()));
+ auto *ToDFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, DFP);
+ auto *ToDFOutOfClass = LastDeclMatcher<CXXMethodDecl>().match(
+ ToTU, cxxMethodDecl(hasName("f"), isDefinition()));
+
+ // The definition should be out-of-class.
+ EXPECT_NE(ToBFInClass, ToBFOutOfClass);
+ EXPECT_NE(ToBFInClass->getLexicalDeclContext(),
+ ToBFOutOfClass->getLexicalDeclContext());
+ EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB);
+ EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU);
+
+ EXPECT_NE(ToDFInClass, ToDFOutOfClass);
+ EXPECT_NE(ToDFInClass->getLexicalDeclContext(),
+ ToDFOutOfClass->getLexicalDeclContext());
+ EXPECT_EQ(ToDFOutOfClass->getDeclContext(), ToD);
+ EXPECT_EQ(ToDFOutOfClass->getLexicalDeclContext(), ToTU);
+
+ // Check that the redecl chain is intact.
+ EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass);
+ 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"));
+
+ TranslationUnitDecl *FromTu = getTuDecl(Code, Lang_C, "input0.c");
+
+ auto *From0 = FirstDeclMatcher<VarDecl>().match(FromTu, Pattern);
+ auto *From1 = LastDeclMatcher<VarDecl>().match(FromTu, Pattern);
+
+ auto *To0 = Import(From0, Lang_C);
+ auto *To1 = Import(From1, Lang_C);
+
+ EXPECT_TRUE(To0);
+ ASSERT_TRUE(To1);
+ EXPECT_NE(To0, To1);
+ EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
+TEST_P(ImportFunctions, ImportFromDifferentScopedAnonNamespace) {
+ TranslationUnitDecl *FromTu = getTuDecl(
+ "namespace NS0 { namespace { void f(); } }"
+ "namespace NS1 { namespace { void f(); } }",
+ Lang_CXX, "input0.cc");
+ auto Pattern = functionDecl(hasName("f"));
+
+ auto *FromF0 = FirstDeclMatcher<FunctionDecl>().match(FromTu, Pattern);
+ auto *FromF1 = LastDeclMatcher<FunctionDecl>().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_FALSE(ToF1->getPreviousDecl());
+}
+
+TEST_P(ImportFunctions, ImportFunctionFromUnnamedNamespace) {
+ {
+ Decl *FromTU = getTuDecl("namespace { void f() {} } void g0() { f(); }",
+ Lang_CXX, "input0.cc");
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("g0")));
+
+ Import(FromD, Lang_CXX);
+ }
+ {
+ Decl *FromTU =
+ getTuDecl("namespace { void f() { int a; } } void g1() { f(); }",
+ Lang_CXX, "input1.cc");
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("g1")));
+ Import(FromD, Lang_CXX);
+ }
+
+ Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))),
+ 2u);
+}
+
+TEST_P(ImportFunctions, ImportImplicitFunctionsInLambda) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ void foo() {
+ (void)[]() { ; };
+ }
+ )",
+ Lang_CXX11);
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("foo")));
+ auto *ToD = Import(FromD, Lang_CXX);
+ EXPECT_TRUE(ToD);
+ CXXRecordDecl *LambdaRec =
+ cast<LambdaExpr>(cast<CStyleCastExpr>(
+ *cast<CompoundStmt>(ToD->getBody())->body_begin())
+ ->getSubExpr())
+ ->getLambdaClass();
+ EXPECT_TRUE(LambdaRec->getDestructor());
+}
+
+TEST_P(ImportFunctions,
+ CallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct X {
+ template <typename T>
+ void foo(){}
+ };
+ void f() {
+ X x;
+ x.foo<int>();
+ }
+ )",
+ Lang_CXX);
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ auto *ToD = Import(FromD, Lang_CXX);
+ EXPECT_TRUE(ToD);
+ EXPECT_TRUE(MatchVerifier<FunctionDecl>().match(
+ ToD, functionDecl(hasName("f"), hasDescendant(declRefExpr()))));
+}
+
+TEST_P(ImportFunctions,
+ DependentCallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct X {
+ template <typename T>
+ void foo(){}
+ };
+ template <typename T>
+ void f() {
+ X x;
+ x.foo<T>();
+ }
+ void g() {
+ f<int>();
+ }
+ )",
+ Lang_CXX);
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("g")));
+ auto *ToD = Import(FromD, Lang_CXX);
+ EXPECT_TRUE(ToD);
+ Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ EXPECT_TRUE(MatchVerifier<TranslationUnitDecl>().match(
+ ToTU, translationUnitDecl(hasDescendant(
+ functionDecl(hasName("f"), hasDescendant(declRefExpr()))))));
+}
+
struct ImportFriendFunctions : ImportFunctions {};
TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainProto) {
@@ -2701,7 +3249,7 @@ TEST_P(ImportExpr, UnresolvedMemberExpr) {
compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
}
-class ImportImplicitMethods : public ASTImporterTestBase {
+class ImportImplicitMethods : public ASTImporterOptionSpecificTestBase {
public:
static constexpr auto DefaultCode = R"(
struct A { int x; };
@@ -2813,7 +3361,7 @@ TEST_P(ImportImplicitMethods, DoNotImportOtherMethod) {
testNoImportOf(cxxMethodDecl(hasName("f")), Code);
}
-TEST_P(ASTImporterTestBase, ImportOfEquivalentRecord) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentRecord) {
Decl *ToR1;
{
Decl *FromTU = getTuDecl(
@@ -2837,7 +3385,7 @@ TEST_P(ASTImporterTestBase, ImportOfEquivalentRecord) {
EXPECT_EQ(ToR1, ToR2);
}
-TEST_P(ASTImporterTestBase, ImportOfNonEquivalentRecord) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentRecord) {
Decl *ToR1;
{
Decl *FromTU = getTuDecl(
@@ -2857,7 +3405,7 @@ TEST_P(ASTImporterTestBase, ImportOfNonEquivalentRecord) {
EXPECT_NE(ToR1, ToR2);
}
-TEST_P(ASTImporterTestBase, ImportOfEquivalentField) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentField) {
Decl *ToF1;
{
Decl *FromTU = getTuDecl(
@@ -2877,7 +3425,7 @@ TEST_P(ASTImporterTestBase, ImportOfEquivalentField) {
EXPECT_EQ(ToF1, ToF2);
}
-TEST_P(ASTImporterTestBase, ImportOfNonEquivalentField) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentField) {
Decl *ToF1;
{
Decl *FromTU = getTuDecl(
@@ -2897,7 +3445,7 @@ TEST_P(ASTImporterTestBase, ImportOfNonEquivalentField) {
EXPECT_NE(ToF1, ToF2);
}
-TEST_P(ASTImporterTestBase, ImportOfEquivalentMethod) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentMethod) {
Decl *ToM1;
{
Decl *FromTU = getTuDecl(
@@ -2917,7 +3465,7 @@ TEST_P(ASTImporterTestBase, ImportOfEquivalentMethod) {
EXPECT_EQ(ToM1, ToM2);
}
-TEST_P(ASTImporterTestBase, ImportOfNonEquivalentMethod) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentMethod) {
Decl *ToM1;
{
Decl *FromTU = getTuDecl(
@@ -2939,7 +3487,8 @@ TEST_P(ASTImporterTestBase, ImportOfNonEquivalentMethod) {
EXPECT_NE(ToM1, ToM2);
}
-TEST_P(ASTImporterTestBase, ImportUnnamedStructsWithRecursingField) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportUnnamedStructsWithRecursingField) {
Decl *FromTU = getTuDecl(
R"(
struct A {
@@ -2971,7 +3520,7 @@ TEST_P(ASTImporterTestBase, ImportUnnamedStructsWithRecursingField) {
R1, recordDecl(has(fieldDecl(hasName("next"))))));
}
-TEST_P(ASTImporterTestBase, ImportUnnamedFieldsInCorrectOrder) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportUnnamedFieldsInCorrectOrder) {
Decl *FromTU = getTuDecl(
R"(
void f(int X, int Y, bool Z) {
@@ -3006,7 +3555,8 @@ TEST_P(ASTImporterTestBase, ImportUnnamedFieldsInCorrectOrder) {
EXPECT_EQ(FromIndex, 3u);
}
-TEST_P(ASTImporterTestBase, MergeFieldDeclsOfClassTemplateSpecialization) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ MergeFieldDeclsOfClassTemplateSpecialization) {
std::string ClassTemplate =
R"(
template <typename T>
@@ -3051,7 +3601,8 @@ TEST_P(ASTImporterTestBase, MergeFieldDeclsOfClassTemplateSpecialization) {
EXPECT_TRUE(ToField->getInClassInitializer());
}
-TEST_P(ASTImporterTestBase, MergeFunctionOfClassTemplateSpecialization) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ MergeFunctionOfClassTemplateSpecialization) {
std::string ClassTemplate =
R"(
template <typename T>
@@ -3092,7 +3643,7 @@ TEST_P(ASTImporterTestBase, MergeFunctionOfClassTemplateSpecialization) {
EXPECT_TRUE(ToFun->hasBody());
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ODRViolationOfClassTemplateSpecializationsShouldBeReported) {
std::string ClassTemplate =
R"(
@@ -3131,15 +3682,14 @@ TEST_P(ASTImporterTestBase,
// The second specialization is different from the first, thus it violates
// ODR, consequently we expect to keep the first specialization only, which is
// already in the "To" context.
- EXPECT_TRUE(ImportedSpec);
- auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
- ToTU, classTemplateSpecializationDecl(hasName("X")));
- EXPECT_EQ(ImportedSpec, ToSpec);
- EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match(
- ToTU, classTemplateSpecializationDecl()));
+ EXPECT_FALSE(ImportedSpec);
+ EXPECT_EQ(1u,
+ DeclCounter<ClassTemplateSpecializationDecl>().match(
+ ToTU, classTemplateSpecializationDecl(hasName("X"))));
}
-TEST_P(ASTImporterTestBase, MergeCtorOfClassTemplateSpecialization) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ MergeCtorOfClassTemplateSpecialization) {
std::string ClassTemplate =
R"(
template <typename T>
@@ -3180,7 +3730,7 @@ TEST_P(ASTImporterTestBase, MergeCtorOfClassTemplateSpecialization) {
EXPECT_TRUE(ToCtor->hasBody());
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ClassTemplatePartialSpecializationsShouldNotBeDuplicated) {
auto Code =
R"(
@@ -3207,7 +3757,8 @@ TEST_P(ASTImporterTestBase,
ToTU, classTemplatePartialSpecializationDecl()));
}
-TEST_P(ASTImporterTestBase, ClassTemplateSpecializationsShouldNotBeDuplicated) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ClassTemplateSpecializationsShouldNotBeDuplicated) {
auto Code =
R"(
// primary template
@@ -3231,7 +3782,8 @@ TEST_P(ASTImporterTestBase, ClassTemplateSpecializationsShouldNotBeDuplicated) {
ToTU, classTemplateSpecializationDecl()));
}
-TEST_P(ASTImporterTestBase, ClassTemplateFullAndPartialSpecsShouldNotBeMixed) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ClassTemplateFullAndPartialSpecsShouldNotBeMixed) {
std::string PrimaryTemplate =
R"(
template<class T1, class T2, int I>
@@ -3263,7 +3815,8 @@ TEST_P(ASTImporterTestBase, ClassTemplateFullAndPartialSpecsShouldNotBeMixed) {
unless(classTemplatePartialSpecializationDecl()))));
}
-TEST_P(ASTImporterTestBase, InitListExprValueKindShouldBeImported) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ InitListExprValueKindShouldBeImported) {
Decl *TU = getTuDecl(
R"(
const int &init();
@@ -3282,7 +3835,7 @@ TEST_P(ASTImporterTestBase, InitListExprValueKindShouldBeImported) {
EXPECT_TRUE(ToInitExpr->isGLValue());
}
-struct ImportVariables : ASTImporterTestBase {};
+struct ImportVariables : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportVariables, ImportOfOneDeclBringsInTheWholeChain) {
Decl *FromTU = getTuDecl(
@@ -3370,155 +3923,7 @@ TEST_P(ImportVariables, InitAndDefinitionAreInTheFromContext) {
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);
-}
-
-TEST_P(ImportClasses, ImportDefinitionWhenProtoIsInToContext) {
- Decl *ToTU = getToTuDecl("struct X;", Lang_C);
- Decl *FromTU1 = getTuDecl("struct X {};", Lang_C, "input1.cc");
- auto Pattern = recordDecl(hasName("X"), unless(isImplicit()));
- auto ToProto = FirstDeclMatcher<RecordDecl>().match(ToTU, Pattern);
- auto FromDef = FirstDeclMatcher<RecordDecl>().match(FromTU1, Pattern);
-
- Decl *ImportedDef = Import(FromDef, Lang_C);
-
- EXPECT_NE(ImportedDef, ToProto);
- EXPECT_EQ(DeclCounter<RecordDecl>().match(ToTU, Pattern), 2u);
- auto ToDef = LastDeclMatcher<RecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedDef == ToDef);
- EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
- EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
- EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
-}
+struct ImportClasses : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportClasses, ImportDefinitionWhenProtoIsInNestedToContext) {
Decl *ToTU = getToTuDecl("struct A { struct X *Xp; };", Lang_C);
@@ -3578,171 +3983,576 @@ TEST_P(ImportClasses, ImportNestedPrototypeThenDefinition) {
EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
}
-struct ImportClassTemplates : ASTImporterTestBase {};
+// 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()));
+ }
+};
-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);
+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()));
+ }
+};
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
+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"));
+ }
+};
- 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());
-}
+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()));
+ }
+};
-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());
-}
+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()));
+ }
+};
-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);
+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());
+ }
+};
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
+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()));
+ }
+};
- 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);
+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;
+ }
- Decl *ImportedDef = Import(FromDef, Lang_CXX);
- Decl *ImportedProto = Import(FromProto, Lang_CXX);
- Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+ // 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;
+ }
+ }
- 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();
+ // The rest: Classes, Functions, etc.
+ EXPECT_EQ(Current->getPreviousDecl(), Prev);
+ }
- 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());
-}
+ 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);
+ }
-struct ImportFriendClasses : ASTImporterTestBase {};
+ 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 {};
TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
Decl *FromTU = getTuDecl(
@@ -3982,7 +4792,7 @@ TEST_P(ImportFriendClasses, ImportOfClassDefinitionAndFwdFriendShouldBeLinked) {
EXPECT_EQ(ImportedFwd, ImportedDef->getPreviousDecl());
}
-TEST_P(ASTImporterTestBase, FriendFunInClassTemplate) {
+TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
auto *Code = R"(
template <class T>
struct X {
@@ -4000,7 +4810,7 @@ TEST_P(ASTImporterTestBase, FriendFunInClassTemplate) {
EXPECT_EQ(ImportedFoo, ToFoo);
}
-struct DeclContextTest : ASTImporterTestBase {};
+struct DeclContextTest : ASTImporterOptionSpecificTestBase {};
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
Decl *TU = getTuDecl(
@@ -4063,7 +4873,8 @@ TEST_P(DeclContextTest,
EXPECT_FALSE(DC->containsDecl(A0));
}
-struct ImportFunctionTemplateSpecializations : ASTImporterTestBase {};
+struct ImportFunctionTemplateSpecializations
+ : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportFunctionTemplateSpecializations,
TUshouldNotContainFunctionTemplateImplicitInstantiation) {
@@ -4200,185 +5011,7 @@ TEST_P(ImportFunctionTemplateSpecializations,
DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))));
}
-TEST_P(ImportFunctionTemplateSpecializations,
- ImportPrototypes) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Proto of the specialization.
- template <>
- void f<int>();
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input1.cc");
- auto *FromD = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- // Check that they are part of the same redecl chain.
- EXPECT_EQ(To1->getCanonicalDecl(), To0->getCanonicalDecl());
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, ImportDefinitions) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization and definition.
- template <>
- void f<int>() {}
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
-
- auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
- ToTU, functionTemplateDecl());
- auto *FirstSpecD = *(TemplateD->spec_begin());
- EXPECT_EQ(FirstSpecD->getCanonicalDecl(), To0->getCanonicalDecl());
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, PrototypeThenPrototype) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization proto.
- template <>
- void f<int>();
- // Specialization proto.
- template <>
- void f<int>();
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, PrototypeThenDefinition) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization proto.
- template <>
- void f<int>();
- // Specialization definition.
- template <>
- void f<int>() {}
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_TRUE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, DefinitionThenPrototype) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization definition.
- template <>
- void f<int>() {}
- // Specialization proto.
- template <>
- void f<int>();
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportShouldNotReportFalseODRErrorWhenRecordIsBeingDefined) {
{
Decl *FromTU = getTuDecl(
@@ -4417,7 +5050,8 @@ TEST_P(ASTImporterTestBase,
}
}
-TEST_P(ASTImporterTestBase, ImportingTypedefShouldImportTheCompleteType) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportingTypedefShouldImportTheCompleteType) {
// We already have an incomplete underlying type in the "To" context.
auto Code =
R"(
@@ -4449,7 +5083,7 @@ TEST_P(ASTImporterTestBase, ImportingTypedefShouldImportTheCompleteType) {
EXPECT_FALSE(ImportedD->getUnderlyingType()->isIncompleteType());
}
-struct ASTImporterLookupTableTest : ASTImporterTestBase {};
+struct ASTImporterLookupTableTest : ASTImporterOptionSpecificTestBase {};
TEST_P(ASTImporterLookupTableTest, OneDecl) {
auto *ToTU = getToTuDecl("int a;", Lang_CXX);
@@ -4595,6 +5229,66 @@ TEST_P(ASTImporterLookupTableTest, LookupFindsOverloadedNames) {
EXPECT_EQ(Res.count(F2), 1u);
}
+TEST_P(ASTImporterLookupTableTest,
+ DifferentOperatorsShouldHaveDifferentResultSet) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ struct X{};
+ void operator+(X, X);
+ void operator-(X, X);
+ )",
+ Lang_CXX);
+
+ ASTImporterLookupTable LT(*ToTU);
+ auto *FPlus = FirstDeclMatcher<FunctionDecl>().match(
+ ToTU, functionDecl(hasOverloadedOperatorName("+")));
+ auto *FMinus = FirstDeclMatcher<FunctionDecl>().match(
+ ToTU, functionDecl(hasOverloadedOperatorName("-")));
+ DeclarationName NamePlus = FPlus->getDeclName();
+ auto ResPlus = LT.lookup(ToTU, NamePlus);
+ EXPECT_EQ(ResPlus.size(), 1u);
+ EXPECT_EQ(ResPlus.count(FPlus), 1u);
+ EXPECT_EQ(ResPlus.count(FMinus), 0u);
+ DeclarationName NameMinus = FMinus->getDeclName();
+ auto ResMinus = LT.lookup(ToTU, NameMinus);
+ EXPECT_EQ(ResMinus.size(), 1u);
+ EXPECT_EQ(ResMinus.count(FMinus), 1u);
+ EXPECT_EQ(ResMinus.count(FPlus), 0u);
+ EXPECT_NE(*ResMinus.begin(), *ResPlus.begin());
+}
+
+TEST_P(ASTImporterLookupTableTest, LookupDeclNamesFromDifferentTUs) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ struct X {};
+ void operator+(X, X);
+ )",
+ Lang_CXX);
+ auto *ToPlus = FirstDeclMatcher<FunctionDecl>().match(
+ ToTU, functionDecl(hasOverloadedOperatorName("+")));
+
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct X {};
+ void operator+(X, X);
+ )",
+ Lang_CXX);
+ auto *FromPlus = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasOverloadedOperatorName("+")));
+
+ // FromPlus have a different TU, thus its DeclarationName is different too.
+ ASSERT_NE(ToPlus->getDeclName(), FromPlus->getDeclName());
+
+ ASTImporterLookupTable LT(*ToTU);
+ auto Res = LT.lookup(ToTU, ToPlus->getDeclName());
+ ASSERT_EQ(Res.size(), 1u);
+ EXPECT_EQ(*Res.begin(), ToPlus);
+
+ // FromPlus have a different TU, thus its DeclarationName is different too.
+ Res = LT.lookup(ToTU, FromPlus->getDeclName());
+ ASSERT_EQ(Res.size(), 0u);
+}
+
static const RecordDecl * getRecordDeclOfFriend(FriendDecl *FD) {
QualType Ty = FD->getFriendType()->getType();
QualType NamedTy = cast<ElaboratedType>(Ty)->getNamedType();
@@ -4866,11 +5560,71 @@ INSTANTIATE_TEST_CASE_P(
ParameterizedTests, CanonicalRedeclChain,
::testing::Values(ArgVector()),);
-auto DefaultTestValuesForRunOptions = ::testing::Values(
- ArgVector(),
- ArgVector{"-fdelayed-template-parsing"},
- ArgVector{"-fms-compatibility"},
- ArgVector{"-fdelayed-template-parsing", "-fms-compatibility"});
+// FIXME This test is disabled currently, upcoming patches will make it
+// possible to enable.
+TEST_P(ASTImporterOptionSpecificTestBase,
+ DISABLED_RedeclChainShouldBeCorrectAmongstNamespaces) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ namespace NS {
+ struct X;
+ struct Y {
+ static const int I = 3;
+ };
+ }
+ namespace NS {
+ struct X { // <--- To be imported
+ void method(int i = Y::I) {}
+ int f;
+ };
+ }
+ )",
+ Lang_CXX);
+ auto *FromFwd = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("X"), unless(isImplicit())));
+ auto *FromDef = LastDeclMatcher<CXXRecordDecl>().match(
+ FromTU,
+ cxxRecordDecl(hasName("X"), isDefinition(), unless(isImplicit())));
+ ASSERT_NE(FromFwd, FromDef);
+ ASSERT_FALSE(FromFwd->isThisDeclarationADefinition());
+ ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+ ASSERT_EQ(FromFwd->getCanonicalDecl(), FromDef->getCanonicalDecl());
+
+ auto *ToDef = cast_or_null<CXXRecordDecl>(Import(FromDef, Lang_CXX));
+ auto *ToFwd = cast_or_null<CXXRecordDecl>(Import(FromFwd, Lang_CXX));
+ EXPECT_NE(ToFwd, ToDef);
+ EXPECT_FALSE(ToFwd->isThisDeclarationADefinition());
+ EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+ EXPECT_EQ(ToFwd->getCanonicalDecl(), ToDef->getCanonicalDecl());
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ // We expect no (ODR) warning during the import.
+ EXPECT_EQ(0u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
+}
+
+struct ImportFriendFunctionTemplates : ASTImporterOptionSpecificTestBase {};
+
+TEST_P(ImportFriendFunctionTemplates, LookupShouldFindPreviousFriend) {
+ Decl *ToTU = getToTuDecl(
+ R"(
+ class X {
+ template <typename T> friend void foo();
+ };
+ )",
+ Lang_CXX);
+ auto *Friend = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ ToTU, functionTemplateDecl(hasName("foo")));
+
+ Decl *FromTU = getTuDecl(
+ R"(
+ template <typename T> void foo();
+ )",
+ Lang_CXX);
+ auto *FromFoo = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ FromTU, functionTemplateDecl(hasName("foo")));
+ auto *Imported = Import(FromFoo, Lang_CXX);
+
+ EXPECT_EQ(Imported->getPreviousDecl(), Friend);
+}
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions, );
@@ -4884,19 +5638,22 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportType,
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportDecl,
DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterTestBase,
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterOptionSpecificTestBase,
+ DefaultTestValuesForRunOptions, );
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedirectingImporterTest,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctions,
DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClasses,
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctionTemplates,
DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctions,
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClasses,
DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClassTemplates,
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctions,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendClasses,