summaryrefslogtreecommitdiffstats
path: root/unittests
diff options
context:
space:
mode:
authorBalazs Keri <1.int32@gmail.com>2018-07-11 09:37:24 +0000
committerBalazs Keri <1.int32@gmail.com>2018-07-11 09:37:24 +0000
commit3ace827b6b1143960561adc4c63e87c67b6ac85b (patch)
treede61db98a12ffe9c9594820aeb22f9de9cd6a56d /unittests
parentbb374a81525139b5ce10f67fb1e8f5eabc4556f0 (diff)
[AST] Structural equivalence of methods
Summary: Added structural equivalence check for C++ methods. Improved structural equivalence tests. Added related ASTImporter tests. Reviewers: a.sidorin, szepet, xazax.hun, martong, a_sidorin Reviewed By: martong, a_sidorin Subscribers: a_sidorin, rnkovacs, cfe-commits Differential Revision: https://reviews.llvm.org/D48628 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@336776 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests')
-rw-r--r--unittests/AST/ASTImporterTest.cpp126
-rw-r--r--unittests/AST/StructuralEquivalenceTest.cpp448
2 files changed, 519 insertions, 55 deletions
diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp
index 34ed5b93a8..50f7285a39 100644
--- a/unittests/AST/ASTImporterTest.cpp
+++ b/unittests/AST/ASTImporterTest.cpp
@@ -2243,6 +2243,132 @@ TEST_P(ImportExpr, UnresolvedMemberExpr) {
compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
}
+TEST_P(ASTImporterTestBase, ImportOfEquivalentRecord) {
+ Decl *ToR1;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { };", Lang_CXX, "input0.cc");
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A")));
+
+ ToR1 = Import(FromR, Lang_CXX);
+ }
+
+ Decl *ToR2;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { };", Lang_CXX, "input1.cc");
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A")));
+
+ ToR2 = Import(FromR, Lang_CXX);
+ }
+
+ EXPECT_EQ(ToR1, ToR2);
+}
+
+TEST_P(ASTImporterTestBase, ImportOfNonEquivalentRecord) {
+ Decl *ToR1;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { int x; };", Lang_CXX, "input0.cc");
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A")));
+ ToR1 = Import(FromR, Lang_CXX);
+ }
+ Decl *ToR2;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { unsigned x; };", Lang_CXX, "input1.cc");
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A")));
+ ToR2 = Import(FromR, Lang_CXX);
+ }
+ EXPECT_NE(ToR1, ToR2);
+}
+
+TEST_P(ASTImporterTestBase, ImportOfEquivalentField) {
+ Decl *ToF1;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { int x; };", Lang_CXX, "input0.cc");
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(
+ FromTU, fieldDecl(hasName("x")));
+ ToF1 = Import(FromF, Lang_CXX);
+ }
+ Decl *ToF2;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { int x; };", Lang_CXX, "input1.cc");
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(
+ FromTU, fieldDecl(hasName("x")));
+ ToF2 = Import(FromF, Lang_CXX);
+ }
+ EXPECT_EQ(ToF1, ToF2);
+}
+
+TEST_P(ASTImporterTestBase, ImportOfNonEquivalentField) {
+ Decl *ToF1;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { int x; };", Lang_CXX, "input0.cc");
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(
+ FromTU, fieldDecl(hasName("x")));
+ ToF1 = Import(FromF, Lang_CXX);
+ }
+ Decl *ToF2;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { unsigned x; };", Lang_CXX, "input1.cc");
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(
+ FromTU, fieldDecl(hasName("x")));
+ ToF2 = Import(FromF, Lang_CXX);
+ }
+ EXPECT_NE(ToF1, ToF2);
+}
+
+TEST_P(ASTImporterTestBase, ImportOfEquivalentMethod) {
+ Decl *ToM1;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { void x(); }; void A::x() { }", Lang_CXX, "input0.cc");
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("x"), isDefinition()));
+ ToM1 = Import(FromM, Lang_CXX);
+ }
+ Decl *ToM2;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { void x(); }; void A::x() { }", Lang_CXX, "input1.cc");
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("x"), isDefinition()));
+ ToM2 = Import(FromM, Lang_CXX);
+ }
+ EXPECT_EQ(ToM1, ToM2);
+}
+
+TEST_P(ASTImporterTestBase, ImportOfNonEquivalentMethod) {
+ Decl *ToM1;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { void x(); }; void A::x() { }",
+ Lang_CXX, "input0.cc");
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("x"), isDefinition()));
+ ToM1 = Import(FromM, Lang_CXX);
+ }
+ Decl *ToM2;
+ {
+ Decl *FromTU = getTuDecl(
+ "struct A { void x() const; }; void A::x() const { }",
+ Lang_CXX, "input1.cc");
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("x"), isDefinition()));
+ ToM2 = Import(FromM, Lang_CXX);
+ }
+ EXPECT_NE(ToM1, ToM2);
+}
+
struct DeclContextTest : ASTImporterTestBase {};
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
diff --git a/unittests/AST/StructuralEquivalenceTest.cpp b/unittests/AST/StructuralEquivalenceTest.cpp
index a8ac79205d..16998f2420 100644
--- a/unittests/AST/StructuralEquivalenceTest.cpp
+++ b/unittests/AST/StructuralEquivalenceTest.cpp
@@ -18,13 +18,13 @@ struct StructuralEquivalenceTest : ::testing::Test {
std::unique_ptr<ASTUnit> AST0, AST1;
std::string Code0, Code1; // Buffers for SourceManager
- // Get a pair of Decl pointers to the synthetised declarations from the given
- // code snipets. By default we search for the unique Decl with name 'foo' in
- // both snippets.
- std::tuple<NamedDecl *, NamedDecl *>
- makeNamedDecls(const std::string &SrcCode0, const std::string &SrcCode1,
- Language Lang, const char *const Identifier = "foo") {
-
+ // Get a pair of node pointers into the synthesized AST from the given code
+ // snippets. To determine the returned node, a separate matcher is specified
+ // for both snippets. The first matching node is returned.
+ template <typename NodeType, typename MatcherType>
+ std::tuple<NodeType *, NodeType *> makeDecls(
+ const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
+ const MatcherType &Matcher0, const MatcherType &Matcher1) {
this->Code0 = SrcCode0;
this->Code1 = SrcCode1;
ArgVector Args = getBasicRunOptionsForLanguage(Lang);
@@ -34,28 +34,32 @@ struct StructuralEquivalenceTest : ::testing::Test {
AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
- ASTContext &Ctx0 = AST0->getASTContext(), &Ctx1 = AST1->getASTContext();
-
- auto getDecl = [](ASTContext &Ctx, const std::string &Name) -> NamedDecl * {
- IdentifierInfo *SearchedII = &Ctx.Idents.get(Name);
- assert(SearchedII && "Declaration with the identifier "
- "should be specified in test!");
- DeclarationName SearchDeclName(SearchedII);
- SmallVector<NamedDecl *, 4> FoundDecls;
- Ctx.getTranslationUnitDecl()->localUncachedLookup(SearchDeclName,
- FoundDecls);
+ NodeType *D0 = FirstDeclMatcher<NodeType>().match(
+ AST0->getASTContext().getTranslationUnitDecl(), Matcher0);
+ NodeType *D1 = FirstDeclMatcher<NodeType>().match(
+ AST1->getASTContext().getTranslationUnitDecl(), Matcher1);
- // We should find one Decl but one only.
- assert(FoundDecls.size() == 1);
+ return std::make_tuple(D0, D1);
+ }
- return FoundDecls[0];
- };
+ // Get a pair of node pointers into the synthesized AST from the given code
+ // snippets. The same matcher is used for both snippets.
+ template <typename NodeType, typename MatcherType>
+ std::tuple<NodeType *, NodeType *> makeDecls(
+ const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
+ const MatcherType &AMatcher) {
+ return makeDecls<NodeType, MatcherType>(
+ SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
+ }
- NamedDecl *D0 = getDecl(Ctx0, Identifier);
- NamedDecl *D1 = getDecl(Ctx1, Identifier);
- assert(D0);
- assert(D1);
- return std::make_tuple(D0, D1);
+ // Get a pair of Decl pointers to the synthesized declarations from the given
+ // code snippets. We search for the first NamedDecl with given name in both
+ // snippets.
+ std::tuple<NamedDecl *, NamedDecl *> makeNamedDecls(
+ const std::string &SrcCode0, const std::string &SrcCode1,
+ Language Lang, const char *const Identifier = "foo") {
+ auto Matcher = namedDecl(hasName(Identifier));
+ return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
}
bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) {
@@ -110,35 +114,29 @@ TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) {
}
TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {
- auto Decls = makeNamedDecls(
- "template <class T> struct foo; template<> struct foo<int>{};",
- "template <class T> struct foo; template<> struct foo<signed int>{};",
- Lang_CXX);
- ClassTemplateSpecializationDecl *Spec0 =
- *cast<ClassTemplateDecl>(get<0>(Decls))->spec_begin();
- ClassTemplateSpecializationDecl *Spec1 =
- *cast<ClassTemplateDecl>(get<1>(Decls))->spec_begin();
- ASSERT_TRUE(Spec0 != nullptr);
- ASSERT_TRUE(Spec1 != nullptr);
+ auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
+ R"(template <class T> struct foo; template<> struct foo<int>{};)",
+ R"(template <class T> struct foo; template<> struct foo<signed int>{};)",
+ Lang_CXX,
+ classTemplateSpecializationDecl());
+ auto Spec0 = get<0>(Decls);
+ auto Spec1 = get<1>(Decls);
EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));
}
TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {
- auto Decls = makeNamedDecls(
- "template <class T> struct foo; template<> struct foo<char>{};",
- "template <class T> struct foo; template<> struct foo<signed char>{};",
- Lang_CXX);
- ClassTemplateSpecializationDecl *Spec0 =
- *cast<ClassTemplateDecl>(get<0>(Decls))->spec_begin();
- ClassTemplateSpecializationDecl *Spec1 =
- *cast<ClassTemplateDecl>(get<1>(Decls))->spec_begin();
- ASSERT_TRUE(Spec0 != nullptr);
- ASSERT_TRUE(Spec1 != nullptr);
+ auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
+ R"(template <class T> struct foo; template<> struct foo<char>{};)",
+ R"(template <class T> struct foo; template<> struct foo<signed char>{};)",
+ Lang_CXX,
+ classTemplateSpecializationDecl());
+ auto Spec0 = get<0>(Decls);
+ auto Spec1 = get<1>(Decls);
EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
}
TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
- auto Decls = makeNamedDecls(
+ auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
R"(
struct true_type{};
template <class T> struct foo;
@@ -149,14 +147,9 @@ TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
template <class T> struct foo;
template<> struct foo<signed char> : true_type {};
)",
- Lang_CXX);
- ClassTemplateSpecializationDecl *Spec0 =
- *cast<ClassTemplateDecl>(get<0>(Decls))->spec_begin();
- ClassTemplateSpecializationDecl *Spec1 =
- *cast<ClassTemplateDecl>(get<1>(Decls))->spec_begin();
- ASSERT_TRUE(Spec0 != nullptr);
- ASSERT_TRUE(Spec1 != nullptr);
- EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
+ Lang_CXX,
+ classTemplateSpecializationDecl());
+ EXPECT_FALSE(testStructuralMatch(Decls));
}
// This test is disabled for now.
@@ -203,5 +196,350 @@ TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
EXPECT_FALSE(testStructuralMatch(Decls));
}
+struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
+};
+
+TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
+ auto t = makeNamedDecls("void foo(int&);",
+ "void foo(const int&);", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
+ auto t = makeNamedDecls("void foo(int);",
+ "void foo(const int);", Lang_CXX);
+ EXPECT_TRUE(testStructuralMatch(t));
+ // consider this OK
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, Throw) {
+ auto t = makeNamedDecls("void foo();",
+ "void foo() throw();", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
+ auto t = makeNamedDecls("void foo();",
+ "void foo() noexcept;", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
+ auto t = makeNamedDecls("void foo() throw();",
+ "void foo() noexcept;", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
+ auto t = makeNamedDecls("void foo() throw();",
+ "void foo() noexcept(false);", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
+ auto t = makeNamedDecls("void foo() throw();",
+ "void foo() noexcept(true);", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
+ // The expression is not checked yet.
+ auto t = makeNamedDecls("void foo() noexcept(false);",
+ "void foo() noexcept(true);", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
+ auto t = makeNamedDecls("void foo() noexcept(false);",
+ "void foo() noexcept(false);", Lang_CXX11);
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
+ auto t = makeNamedDecls("void foo() noexcept;",
+ "void foo() noexcept(false);", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
+ auto t = makeNamedDecls("void foo() noexcept;",
+ "void foo() noexcept(true);", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
+ auto t = makeNamedDecls("char foo();",
+ "int foo();", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
+ auto t = makeNamedDecls("char foo();",
+ "const char foo();", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
+ auto t = makeNamedDecls("char &foo();",
+ "char &&foo();", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
+ auto t = makeNamedDecls("void foo(int);",
+ "void foo(int, int);", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
+ auto t = makeNamedDecls("void foo(int);",
+ "void foo(char);", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
+ auto t = makeNamedDecls("void foo(int a);",
+ "void foo(int b);", Lang_CXX);
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
+ auto t = makeNamedDecls("void foo(int x...);",
+ "void foo(int x);", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
+ auto t = makeNamedDecls("void foo(int *);",
+ "void foo(int);", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
+ auto t = makeNamedDecls(
+ "void ((foo))();",
+ "void foo();",
+ Lang_CXX);
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
+ auto t = makeNamedDecls(
+ "void (foo)() throw(int);",
+ "void (foo)() noexcept;",
+ Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
+ auto t = makeNamedDecls(
+ "struct A { void (foo)() const; };",
+ "struct A { void (foo)(); };",
+ Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
+};
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
+ auto t = makeDecls<CXXMethodDecl>(
+ "struct X { void foo(); };",
+ "struct X { virtual void foo(); };", Lang_CXX,
+ cxxMethodDecl(hasName("foo")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
+ auto t = makeNamedDecls("struct X { virtual void foo(); };",
+ "struct X { virtual void foo() = 0; };", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
+ // The final-ness is not checked yet.
+ auto t = makeNamedDecls("struct X { virtual void foo(); };",
+ "struct X { virtual void foo() final; };", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
+ auto t = makeNamedDecls("struct X { void foo(); };",
+ "struct X { void foo() const; };", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
+ auto t = makeNamedDecls("struct X { void foo(); };",
+ "struct X { static void foo(); };", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
+ auto t = makeNamedDecls("struct X { void foo(); };",
+ "struct X { void foo() &&; };", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
+ auto t = makeNamedDecls("struct X { void foo() &; };",
+ "struct X { void foo() &&; };", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
+ auto t = makeDecls<CXXMethodDecl>(
+ "struct X { public: void foo(); };",
+ "struct X { private: void foo(); };", Lang_CXX,
+ cxxMethodDecl(hasName("foo")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
+ auto t = makeNamedDecls("struct X { void foo(); };",
+ "struct X { void foo() = delete; };", Lang_CXX11);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
+ auto t = makeDecls<FunctionDecl>(
+ "void foo();", "struct foo { foo(); };", Lang_CXX,
+ functionDecl(), cxxConstructorDecl());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
+ auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
+ "struct X { X(int); };", Lang_CXX,
+ cxxConstructorDecl());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
+ auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
+ "struct X { explicit X(int); };",
+ Lang_CXX11,
+ cxxConstructorDecl());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
+ auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
+ "struct X { X() = default; };",
+ Lang_CXX11,
+ cxxConstructorDecl());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
+ auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
+ "struct X { operator char(); };",
+ Lang_CXX11,
+ cxxConversionDecl());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
+ auto t = makeDecls<FunctionDecl>(
+ "struct X { int operator +(int); };",
+ "struct X { int operator -(int); };", Lang_CXX,
+ functionDecl(hasOverloadedOperatorName("+")),
+ functionDecl(hasOverloadedOperatorName("-")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
+ auto t = makeDecls<FunctionDecl>(
+ "struct X { virtual void f(); }; void X::f() { }",
+ "struct X { virtual void f() { }; };",
+ Lang_CXX,
+ functionDecl(allOf(hasName("f"), isDefinition())));
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
+ auto t = makeDecls<FunctionDecl>(
+ "struct X { virtual void f(); }; void X::f() { }",
+ "struct X { void f(); }; void X::f() { }",
+ Lang_CXX,
+ functionDecl(allOf(hasName("f"), isDefinition())));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
+};
+
+TEST_F(StructuralEquivalenceRecordTest, Name) {
+ auto t = makeDecls<CXXRecordDecl>(
+ "struct A{ };",
+ "struct B{ };",
+ Lang_CXX,
+ cxxRecordDecl());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceRecordTest, Fields) {
+ auto t = makeNamedDecls(
+ "struct foo{ int x; };",
+ "struct foo{ char x; };",
+ Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
+ // Currently, methods of a class are not checked at class equivalence.
+ auto t = makeNamedDecls(
+ "struct foo{ int x(); };",
+ "struct foo{ char x(); };",
+ Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceRecordTest, Bases) {
+ auto t = makeNamedDecls(
+ "struct A{ }; struct foo: A { };",
+ "struct B{ }; struct foo: B { };",
+ Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
+ auto t = makeNamedDecls(
+ "struct A{ }; struct foo: A { };",
+ "struct A{ }; struct foo: virtual A { };",
+ Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
+ // Access specifier in inheritance is not checked yet.
+ auto t = makeNamedDecls(
+ "struct A{ }; struct foo: public A { };",
+ "struct A{ }; struct foo: private A { };",
+ Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceRecordTest, Match) {
+ auto Code = R"(
+ struct A{ };
+ struct B{ };
+ struct foo: A, virtual B {
+ void x();
+ int a;
+ };
+ )";
+ auto t = makeNamedDecls(Code, Code, Lang_CXX);
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
+ auto t = makeNamedDecls(
+ "struct A{ }; struct B{ }; void foo(A a, A b);",
+ "struct A{ }; struct B{ }; void foo(A a, B b);",
+ Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
} // end namespace ast_matchers
} // end namespace clang