|
@@ -42,6 +42,21 @@ struct StructuralEquivalenceTest : ::testing::Test {
|
|
|
return std::make_tuple(D0, D1);
|
|
|
}
|
|
|
|
|
|
+ std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> makeTuDecls(
|
|
|
+ const std::string &SrcCode0, const std::string &SrcCode1, Language Lang) {
|
|
|
+ this->Code0 = SrcCode0;
|
|
|
+ this->Code1 = SrcCode1;
|
|
|
+ ArgVector Args = getBasicRunOptionsForLanguage(Lang);
|
|
|
+
|
|
|
+ const char *const InputFileName = "input.cc";
|
|
|
+
|
|
|
+ AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
|
|
|
+ AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
|
|
|
+
|
|
|
+ return std::make_tuple(AST0->getASTContext().getTranslationUnitDecl(),
|
|
|
+ AST1->getASTContext().getTranslationUnitDecl());
|
|
|
+ }
|
|
|
+
|
|
|
// 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>
|
|
@@ -62,7 +77,7 @@ struct StructuralEquivalenceTest : ::testing::Test {
|
|
|
return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
|
|
|
}
|
|
|
|
|
|
- bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) {
|
|
|
+ bool testStructuralMatch(Decl *D0, Decl *D1) {
|
|
|
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
|
|
|
StructuralEquivalenceContext Ctx(
|
|
|
D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls,
|
|
@@ -70,7 +85,7 @@ struct StructuralEquivalenceTest : ::testing::Test {
|
|
|
return Ctx.IsStructurallyEquivalent(D0, D1);
|
|
|
}
|
|
|
|
|
|
- bool testStructuralMatch(std::tuple<NamedDecl *, NamedDecl *> t) {
|
|
|
+ bool testStructuralMatch(std::tuple<Decl *, Decl *> t) {
|
|
|
return testStructuralMatch(get<0>(t), get<1>(t));
|
|
|
}
|
|
|
};
|
|
@@ -468,6 +483,11 @@ TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
|
|
|
}
|
|
|
|
|
|
struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
|
|
|
+ // FIXME Use a common getRecordDecl with ASTImporterTest.cpp!
|
|
|
+ RecordDecl *getRecordDecl(FieldDecl *FD) {
|
|
|
+ auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr());
|
|
|
+ return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
|
|
|
+ };
|
|
|
};
|
|
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, Name) {
|
|
@@ -535,6 +555,70 @@ TEST_F(StructuralEquivalenceRecordTest, Match) {
|
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
|
}
|
|
|
|
|
|
+TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) {
|
|
|
+ auto t = makeTuDecls(
|
|
|
+ R"(
|
|
|
+ struct A {
|
|
|
+ struct {
|
|
|
+ struct A *next;
|
|
|
+ } entry0;
|
|
|
+ struct {
|
|
|
+ struct A *next;
|
|
|
+ } entry1;
|
|
|
+ };
|
|
|
+ )",
|
|
|
+ "", Lang_C);
|
|
|
+ auto *TU = get<0>(t);
|
|
|
+ auto *Entry0 =
|
|
|
+ FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0")));
|
|
|
+ auto *Entry1 =
|
|
|
+ FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1")));
|
|
|
+ auto *R0 = getRecordDecl(Entry0);
|
|
|
+ auto *R1 = getRecordDecl(Entry1);
|
|
|
+
|
|
|
+ ASSERT_NE(R0, R1);
|
|
|
+ EXPECT_TRUE(testStructuralMatch(R0, R0));
|
|
|
+ EXPECT_TRUE(testStructuralMatch(R1, R1));
|
|
|
+ EXPECT_FALSE(testStructuralMatch(R0, R1));
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(StructuralEquivalenceRecordTest,
|
|
|
+ UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) {
|
|
|
+ auto Code =
|
|
|
+ R"(
|
|
|
+ struct A {
|
|
|
+ struct {
|
|
|
+ struct A *next;
|
|
|
+ } entry0;
|
|
|
+ struct {
|
|
|
+ struct A *next;
|
|
|
+ } entry1;
|
|
|
+ };
|
|
|
+ )";
|
|
|
+ auto t = makeTuDecls(Code, Code, Lang_C);
|
|
|
+
|
|
|
+ auto *FromTU = get<0>(t);
|
|
|
+ auto *Entry1 =
|
|
|
+ FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1")));
|
|
|
+
|
|
|
+ auto *ToTU = get<1>(t);
|
|
|
+ auto *Entry0 =
|
|
|
+ FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0")));
|
|
|
+ auto *A =
|
|
|
+ FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A")));
|
|
|
+ A->startDefinition(); // Set isBeingDefined, getDefinition() will return a
|
|
|
+ // nullptr. This may be the case during ASTImport.
|
|
|
+
|
|
|
+ auto *R0 = getRecordDecl(Entry0);
|
|
|
+ auto *R1 = getRecordDecl(Entry1);
|
|
|
+
|
|
|
+ ASSERT_NE(R0, R1);
|
|
|
+ EXPECT_TRUE(testStructuralMatch(R0, R0));
|
|
|
+ EXPECT_TRUE(testStructuralMatch(R1, R1));
|
|
|
+ EXPECT_FALSE(testStructuralMatch(R0, R1));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
|
|
|
auto t = makeNamedDecls(
|
|
|
"struct A{ }; struct B{ }; void foo(A a, A b);",
|