forked from OSchip/llvm-project
417 lines
17 KiB
C++
417 lines
17 KiB
C++
//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Type-parameterized tests for the correct import of Decls with different
|
|
// visibility.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Define this to have ::testing::Combine available.
|
|
// FIXME: Better solution for this?
|
|
#define GTEST_HAS_COMBINE 1
|
|
|
|
#include "ASTImporterFixtures.h"
|
|
|
|
namespace clang {
|
|
namespace ast_matchers {
|
|
|
|
using internal::BindableMatcher;
|
|
|
|
// Type parameters for type-parameterized test fixtures.
|
|
struct GetFunPattern {
|
|
using DeclTy = FunctionDecl;
|
|
BindableMatcher<Decl> operator()() { return functionDecl(hasName("f")); }
|
|
};
|
|
struct GetVarPattern {
|
|
using DeclTy = VarDecl;
|
|
BindableMatcher<Decl> operator()() { return varDecl(hasName("v")); }
|
|
};
|
|
struct GetClassPattern {
|
|
using DeclTy = CXXRecordDecl;
|
|
BindableMatcher<Decl> operator()() { return cxxRecordDecl(hasName("X")); }
|
|
};
|
|
struct GetEnumPattern {
|
|
using DeclTy = EnumDecl;
|
|
BindableMatcher<Decl> operator()() { return enumDecl(hasName("E")); }
|
|
};
|
|
struct GetTypedefNamePattern {
|
|
using DeclTy = TypedefNameDecl;
|
|
BindableMatcher<Decl> operator()() { return typedefNameDecl(hasName("T")); }
|
|
};
|
|
struct GetFunTemplPattern {
|
|
using DeclTy = FunctionTemplateDecl;
|
|
BindableMatcher<Decl> operator()() {
|
|
return functionTemplateDecl(hasName("f"));
|
|
}
|
|
};
|
|
|
|
// Values for the value-parameterized test fixtures.
|
|
// FunctionDecl:
|
|
const auto *ExternF = "void f();";
|
|
const auto *StaticF = "static void f();";
|
|
const auto *AnonF = "namespace { void f(); }";
|
|
// VarDecl:
|
|
const auto *ExternV = "extern int v;";
|
|
const auto *StaticV = "static int v;";
|
|
const auto *AnonV = "namespace { extern int v; }";
|
|
// CXXRecordDecl:
|
|
const auto *ExternC = "class X;";
|
|
const auto *AnonC = "namespace { class X; }";
|
|
// EnumDecl:
|
|
const auto *ExternE = "enum E {};";
|
|
const auto *AnonE = "namespace { enum E {}; }";
|
|
// TypedefNameDecl:
|
|
const auto *ExternTypedef = "typedef int T;";
|
|
const auto *AnonTypedef = "namespace { typedef int T; }";
|
|
const auto *ExternUsing = "using T = int;";
|
|
const auto *AnonUsing = "namespace { using T = int; }";
|
|
// FunctionTemplateDecl:
|
|
const auto *ExternFT = "template <class> void f();";
|
|
const auto *StaticFT = "template <class> static void f();";
|
|
const auto *AnonFT = "namespace { template <class> void f(); }";
|
|
|
|
// 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_CXX14, "input0.cc");
|
|
|
|
auto *FromD0 = FirstDeclMatcher<DeclTy>().match(FromTu, Pattern);
|
|
auto *FromD1 = LastDeclMatcher<DeclTy>().match(FromTu, Pattern);
|
|
|
|
auto *ToD0 = Import(FromD0, Lang_CXX14);
|
|
auto *ToD1 = Import(FromD1, Lang_CXX14);
|
|
|
|
EXPECT_TRUE(ToD0);
|
|
ASSERT_TRUE(ToD1);
|
|
EXPECT_NE(ToD0, ToD1);
|
|
EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
|
|
}
|
|
};
|
|
|
|
// Manual instantiation of the fixture with each type.
|
|
using ImportFunctionsVisibilityChain = ImportVisibilityChain<GetFunPattern>;
|
|
using ImportVariablesVisibilityChain = ImportVisibilityChain<GetVarPattern>;
|
|
using ImportClassesVisibilityChain = ImportVisibilityChain<GetClassPattern>;
|
|
using ImportFunctionTemplatesVisibilityChain =
|
|
ImportVisibilityChain<GetFunTemplPattern>;
|
|
|
|
// Value-parameterized test for functions.
|
|
TEST_P(ImportFunctionsVisibilityChain, ImportChain) {
|
|
TypedTest_ImportChain();
|
|
}
|
|
// Value-parameterized test for variables.
|
|
TEST_P(ImportVariablesVisibilityChain, ImportChain) {
|
|
TypedTest_ImportChain();
|
|
}
|
|
// Value-parameterized test for classes.
|
|
TEST_P(ImportClassesVisibilityChain, ImportChain) {
|
|
TypedTest_ImportChain();
|
|
}
|
|
// Value-parameterized test for function templates.
|
|
TEST_P(ImportFunctionTemplatesVisibilityChain, 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)), );
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ParameterizedTests, ImportClassesVisibilityChain,
|
|
::testing::Combine(
|
|
DefaultTestValuesForRunOptions,
|
|
::testing::Values(ExternC, AnonC)), );
|
|
INSTANTIATE_TEST_CASE_P(ParameterizedTests,
|
|
ImportFunctionTemplatesVisibilityChain,
|
|
::testing::Combine(DefaultTestValuesForRunOptions,
|
|
::testing::Values(ExternFT, StaticFT,
|
|
AnonFT)), );
|
|
|
|
// 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_CXX14);
|
|
TranslationUnitDecl *FromTu =
|
|
getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
|
|
|
|
auto *ToD0 = FirstDeclMatcher<DeclTy>().match(ToTu, getPattern());
|
|
auto *FromD1 = FirstDeclMatcher<DeclTy>().match(FromTu, getPattern());
|
|
|
|
auto *ToD1 = Import(FromD1, Lang_CXX14);
|
|
|
|
ASSERT_TRUE(ToD0);
|
|
ASSERT_TRUE(ToD1);
|
|
EXPECT_NE(ToD0, ToD1);
|
|
|
|
if (shouldBeLinked())
|
|
EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
|
|
else
|
|
EXPECT_FALSE(ToD1->getPreviousDecl());
|
|
}
|
|
|
|
void TypedTest_ImportAfterImport() {
|
|
TranslationUnitDecl *FromTu0 =
|
|
getTuDecl(getCode0(), Lang_CXX14, "input0.cc");
|
|
TranslationUnitDecl *FromTu1 =
|
|
getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
|
|
auto *FromD0 = FirstDeclMatcher<DeclTy>().match(FromTu0, getPattern());
|
|
auto *FromD1 = FirstDeclMatcher<DeclTy>().match(FromTu1, getPattern());
|
|
auto *ToD0 = Import(FromD0, Lang_CXX14);
|
|
auto *ToD1 = Import(FromD1, Lang_CXX14);
|
|
ASSERT_TRUE(ToD0);
|
|
ASSERT_TRUE(ToD1);
|
|
EXPECT_NE(ToD0, ToD1);
|
|
if (shouldBeLinked())
|
|
EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
|
|
else
|
|
EXPECT_FALSE(ToD1->getPreviousDecl());
|
|
}
|
|
|
|
void TypedTest_ImportAfterWithMerge() {
|
|
TranslationUnitDecl *ToTu = getToTuDecl(getCode0(), Lang_CXX14);
|
|
TranslationUnitDecl *FromTu =
|
|
getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
|
|
|
|
auto *ToF0 = FirstDeclMatcher<DeclTy>().match(ToTu, getPattern());
|
|
auto *FromF1 = FirstDeclMatcher<DeclTy>().match(FromTu, getPattern());
|
|
|
|
auto *ToF1 = Import(FromF1, Lang_CXX14);
|
|
|
|
ASSERT_TRUE(ToF0);
|
|
ASSERT_TRUE(ToF1);
|
|
|
|
if (shouldBeLinked())
|
|
EXPECT_EQ(ToF0, ToF1);
|
|
else
|
|
EXPECT_NE(ToF0, ToF1);
|
|
|
|
// We expect no (ODR) warning during the import.
|
|
EXPECT_EQ(0u, ToTu->getASTContext().getDiagnostics().getNumWarnings());
|
|
}
|
|
|
|
void TypedTest_ImportAfterImportWithMerge() {
|
|
TranslationUnitDecl *FromTu0 =
|
|
getTuDecl(getCode0(), Lang_CXX14, "input0.cc");
|
|
TranslationUnitDecl *FromTu1 =
|
|
getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
|
|
auto *FromF0 = FirstDeclMatcher<DeclTy>().match(FromTu0, getPattern());
|
|
auto *FromF1 = FirstDeclMatcher<DeclTy>().match(FromTu1, getPattern());
|
|
auto *ToF0 = Import(FromF0, Lang_CXX14);
|
|
auto *ToF1 = Import(FromF1, Lang_CXX14);
|
|
ASSERT_TRUE(ToF0);
|
|
ASSERT_TRUE(ToF1);
|
|
if (shouldBeLinked())
|
|
EXPECT_EQ(ToF0, ToF1);
|
|
else
|
|
EXPECT_NE(ToF0, ToF1);
|
|
|
|
// We expect no (ODR) warning during the import.
|
|
EXPECT_EQ(0u, ToF0->getTranslationUnitDecl()
|
|
->getASTContext()
|
|
.getDiagnostics()
|
|
.getNumWarnings());
|
|
}
|
|
};
|
|
using ImportFunctionsVisibility = ImportVisibility<GetFunPattern>;
|
|
using ImportVariablesVisibility = ImportVisibility<GetVarPattern>;
|
|
using ImportClassesVisibility = ImportVisibility<GetClassPattern>;
|
|
using ImportEnumsVisibility = ImportVisibility<GetEnumPattern>;
|
|
using ImportTypedefNameVisibility = ImportVisibility<GetTypedefNamePattern>;
|
|
using ImportFunctionTemplatesVisibility = ImportVisibility<GetFunTemplPattern>;
|
|
|
|
// 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();
|
|
}
|
|
// CXXRecordDecl.
|
|
TEST_P(ImportClassesVisibility, ImportAfter) {
|
|
TypedTest_ImportAfter();
|
|
}
|
|
TEST_P(ImportClassesVisibility, ImportAfterImport) {
|
|
TypedTest_ImportAfterImport();
|
|
}
|
|
// EnumDecl.
|
|
TEST_P(ImportEnumsVisibility, ImportAfter) {
|
|
TypedTest_ImportAfterWithMerge();
|
|
}
|
|
TEST_P(ImportEnumsVisibility, ImportAfterImport) {
|
|
TypedTest_ImportAfterImportWithMerge();
|
|
}
|
|
// TypedefNameDecl.
|
|
TEST_P(ImportTypedefNameVisibility, ImportAfter) {
|
|
TypedTest_ImportAfterWithMerge();
|
|
}
|
|
TEST_P(ImportTypedefNameVisibility, ImportAfterImport) {
|
|
TypedTest_ImportAfterImportWithMerge();
|
|
}
|
|
// FunctionTemplateDecl.
|
|
TEST_P(ImportFunctionTemplatesVisibility, ImportAfter) {
|
|
TypedTest_ImportAfter();
|
|
}
|
|
TEST_P(ImportFunctionTemplatesVisibility, ImportAfterImport) {
|
|
TypedTest_ImportAfterImport();
|
|
}
|
|
|
|
const bool ExpectLinkedDeclChain = true;
|
|
const bool ExpectUnlinkedDeclChain = false;
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ParameterizedTests, ImportFunctionsVisibility,
|
|
::testing::Combine(
|
|
DefaultTestValuesForRunOptions,
|
|
::testing::Values(
|
|
std::make_tuple(ExternF, ExternF, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternF, StaticF, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(ExternF, AnonF, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticF, ExternF, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticF, StaticF, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticF, AnonF, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonF, ExternF, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonF, StaticF, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonF, AnonF, ExpectUnlinkedDeclChain))), );
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ParameterizedTests, ImportVariablesVisibility,
|
|
::testing::Combine(
|
|
DefaultTestValuesForRunOptions,
|
|
::testing::Values(
|
|
std::make_tuple(ExternV, ExternV, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternV, StaticV, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(ExternV, AnonV, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticV, ExternV, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticV, StaticV, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticV, AnonV, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonV, ExternV, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonV, StaticV, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonV, AnonV, ExpectUnlinkedDeclChain))), );
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ParameterizedTests, ImportClassesVisibility,
|
|
::testing::Combine(
|
|
DefaultTestValuesForRunOptions,
|
|
::testing::Values(
|
|
std::make_tuple(ExternC, ExternC, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternC, AnonC, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonC, ExternC, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonC, AnonC, ExpectUnlinkedDeclChain))), );
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ParameterizedTests, ImportEnumsVisibility,
|
|
::testing::Combine(
|
|
DefaultTestValuesForRunOptions,
|
|
::testing::Values(
|
|
std::make_tuple(ExternE, ExternE, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternE, AnonE, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonE, ExternE, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonE, AnonE, ExpectUnlinkedDeclChain))), );
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ParameterizedTests, ImportTypedefNameVisibility,
|
|
::testing::Combine(
|
|
DefaultTestValuesForRunOptions,
|
|
::testing::Values(
|
|
std::make_tuple(ExternTypedef, ExternTypedef,
|
|
ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternTypedef, AnonTypedef,
|
|
ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonTypedef, ExternTypedef,
|
|
ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonTypedef, AnonTypedef, ExpectUnlinkedDeclChain),
|
|
|
|
std::make_tuple(ExternUsing, ExternUsing, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternUsing, AnonUsing, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonUsing, ExternUsing, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonUsing, AnonUsing, ExpectUnlinkedDeclChain),
|
|
|
|
std::make_tuple(ExternUsing, ExternTypedef, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternUsing, AnonTypedef, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonUsing, ExternTypedef, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonUsing, AnonTypedef, ExpectUnlinkedDeclChain),
|
|
|
|
std::make_tuple(ExternTypedef, ExternUsing, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternTypedef, AnonUsing, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonTypedef, ExternUsing, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonTypedef, AnonUsing,
|
|
ExpectUnlinkedDeclChain))), );
|
|
INSTANTIATE_TEST_CASE_P(
|
|
ParameterizedTests, ImportFunctionTemplatesVisibility,
|
|
::testing::Combine(
|
|
DefaultTestValuesForRunOptions,
|
|
::testing::Values(
|
|
std::make_tuple(ExternFT, ExternFT, ExpectLinkedDeclChain),
|
|
std::make_tuple(ExternFT, StaticFT, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(ExternFT, AnonFT, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticFT, ExternFT, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticFT, StaticFT, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(StaticFT, AnonFT, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonFT, ExternFT, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonFT, StaticFT, ExpectUnlinkedDeclChain),
|
|
std::make_tuple(AnonFT, AnonFT, ExpectUnlinkedDeclChain))), );
|
|
|
|
} // end namespace ast_matchers
|
|
} // end namespace clang
|