<div dir="ltr">Hi,<div>I am aware of the problem, there should be already a commit to (hopefully) correct the failure.</div><div><br></div><div>Balázs Kéri</div></div><br><div class="gmail_quote"><div dir="ltr">Galina Kistanova <<a href="mailto:gkistanova@gmail.com">gkistanova@gmail.com</a>> ezt írta (időpont: 2018. júl. 11., Sze, 20:01):<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hello Balazs,<br><br>This commit broke at least one of our builders:<br><a href="http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/10897" target="_blank">http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/10897</a><br><br>. . . <br>Failing Tests (1):<br> Clang-Unit :: AST/./ASTTests.exe/StructuralEquivalenceRecordTest.Name<br><br>Please have a look?<br>It is not good idea to keep the bot red for too long. This hides new problem which later hard to track down.<br><br>Thanks<br><br><div>Galina</div><div><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jul 11, 2018 at 2:37 AM, Balazs Keri via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: balazske<br>
Date: Wed Jul 11 02:37:24 2018<br>
New Revision: 336776<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=336776&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=336776&view=rev</a><br>
Log:<br>
[AST] Structural equivalence of methods<br>
<br>
Summary:<br>
Added structural equivalence check for C++ methods.<br>
Improved structural equivalence tests.<br>
Added related ASTImporter tests.<br>
<br>
Reviewers: a.sidorin, szepet, xazax.hun, martong, a_sidorin<br>
<br>
Reviewed By: martong, a_sidorin<br>
<br>
Subscribers: a_sidorin, rnkovacs, cfe-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D48628" rel="noreferrer" target="_blank">https://reviews.llvm.org/D48628</a><br>
<br>
Modified:<br>
cfe/trunk/lib/AST/ASTImporter.cpp<br>
cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp<br>
cfe/trunk/unittests/AST/ASTImporterTest.cpp<br>
cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp<br>
<br>
Modified: cfe/trunk/lib/AST/ASTImporter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=336776&r1=336775&r2=336776&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=336776&r1=336775&r2=336776&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTImporter.cpp Wed Jul 11 02:37:24 2018<br>
@@ -230,6 +230,7 @@ namespace clang {<br>
bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);<br>
bool IsStructuralMatch(FunctionTemplateDecl *From,<br>
FunctionTemplateDecl *To);<br>
+ bool IsStructuralMatch(FunctionDecl *From, FunctionDecl *To);<br>
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);<br>
bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To);<br>
Decl *VisitDecl(Decl *D);<br>
@@ -1525,6 +1526,13 @@ bool ASTNodeImporter::IsStructuralMatch(<br>
return Ctx.IsStructurallyEquivalent(From, To);<br>
}<br>
<br>
+bool ASTNodeImporter::IsStructuralMatch(FunctionDecl *From, FunctionDecl *To) {<br>
+ StructuralEquivalenceContext Ctx(<br>
+ Importer.getFromContext(), Importer.getToContext(),<br>
+ Importer.getNonEquivalentDecls(), false, false);<br>
+ return Ctx.IsStructurallyEquivalent(From, To);<br>
+}<br>
+<br>
bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC,<br>
EnumConstantDecl *ToEC) {<br>
const llvm::APSInt &FromVal = FromEC->getInitVal();<br>
@@ -2433,13 +2441,15 @@ Decl *ASTNodeImporter::VisitFunctionDecl<br>
if (auto *FoundFunction = dyn_cast<FunctionDecl>(FoundDecl)) {<br>
if (FoundFunction->hasExternalFormalLinkage() &&<br>
D->hasExternalFormalLinkage()) {<br>
- if (Importer.IsStructurallyEquivalent(D->getType(), <br>
- FoundFunction->getType())) {<br>
- if (D->doesThisDeclarationHaveABody() &&<br>
- FoundFunction->hasBody())<br>
- return Importer.Imported(D, FoundFunction);<br>
- FoundByLookup = FoundFunction;<br>
- break;<br>
+ if (IsStructuralMatch(D, FoundFunction)) {<br>
+ const FunctionDecl *Definition = nullptr;<br>
+ if (D->doesThisDeclarationHaveABody() &&<br>
+ FoundFunction->hasBody(Definition)) {<br>
+ return Importer.Imported(<br>
+ D, const_cast<FunctionDecl *>(Definition));<br>
+ }<br>
+ FoundByLookup = FoundFunction;<br>
+ break;<br>
}<br>
<br>
// FIXME: Check for overloading more carefully, e.g., by boosting<br>
<br>
Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=336776&r1=336775&r2=336776&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=336776&r1=336775&r2=336776&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Wed Jul 11 02:37:24 2018<br>
@@ -250,6 +250,9 @@ static bool IsStructurallyEquivalent(Str<br>
if (T1.isNull() || T2.isNull())<br>
return T1.isNull() && T2.isNull();<br>
<br>
+ QualType OrigT1 = T1;<br>
+ QualType OrigT2 = T2;<br>
+<br>
if (!Context.StrictTypeSpelling) {<br>
// We aren't being strict about token-to-token equivalence of types,<br>
// so map down to the canonical type.<br>
@@ -422,6 +425,7 @@ static bool IsStructurallyEquivalent(Str<br>
case Type::FunctionProto: {<br>
const auto *Proto1 = cast<FunctionProtoType>(T1);<br>
const auto *Proto2 = cast<FunctionProtoType>(T2);<br>
+<br>
if (Proto1->getNumParams() != Proto2->getNumParams())<br>
return false;<br>
for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {<br>
@@ -431,23 +435,33 @@ static bool IsStructurallyEquivalent(Str<br>
}<br>
if (Proto1->isVariadic() != Proto2->isVariadic())<br>
return false;<br>
- if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())<br>
+<br>
+ if (Proto1->getTypeQuals() != Proto2->getTypeQuals())<br>
+ return false;<br>
+ <br>
+ // Check exceptions, this information is lost in canonical type.<br>
+ const auto *OrigProto1 =<br>
+ cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx));<br>
+ const auto *OrigProto2 =<br>
+ cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx));<br>
+ auto Spec1 = OrigProto1->getExceptionSpecType();<br>
+ auto Spec2 = OrigProto2->getExceptionSpecType();<br>
+ <br>
+ if (Spec1 != Spec2)<br>
return false;<br>
- if (Proto1->getExceptionSpecType() == EST_Dynamic) {<br>
- if (Proto1->getNumExceptions() != Proto2->getNumExceptions())<br>
+ if (Spec1 == EST_Dynamic) {<br>
+ if (OrigProto1->getNumExceptions() != OrigProto2->getNumExceptions())<br>
return false;<br>
- for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {<br>
- if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),<br>
- Proto2->getExceptionType(I)))<br>
+ for (unsigned I = 0, N = OrigProto1->getNumExceptions(); I != N; ++I) {<br>
+ if (!IsStructurallyEquivalent(Context, OrigProto1->getExceptionType(I),<br>
+ OrigProto2->getExceptionType(I)))<br>
return false;<br>
}<br>
- } else if (isComputedNoexcept(Proto1->getExceptionSpecType())) {<br>
- if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),<br>
- Proto2->getNoexceptExpr()))<br>
+ } else if (isComputedNoexcept(Spec1)) {<br>
+ if (!IsStructurallyEquivalent(Context, OrigProto1->getNoexceptExpr(),<br>
+ OrigProto2->getNoexceptExpr()))<br>
return false;<br>
}<br>
- if (Proto1->getTypeQuals() != Proto2->getTypeQuals())<br>
- return false;<br>
<br>
// Fall through to check the bits common with FunctionNoProtoType.<br>
LLVM_FALLTHROUGH;<br>
@@ -830,6 +844,56 @@ static bool IsStructurallyEquivalent(Str<br>
return true;<br>
}<br>
<br>
+/// Determine structural equivalence of two methodss.<br>
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,<br>
+ CXXMethodDecl *Method1,<br>
+ CXXMethodDecl *Method2) {<br>
+ bool PropertiesEqual =<br>
+ Method1->getDeclKind() == Method2->getDeclKind() &&<br>
+ Method1->getRefQualifier() == Method2->getRefQualifier() &&<br>
+ Method1->getAccess() == Method2->getAccess() &&<br>
+ Method1->getOverloadedOperator() == Method2->getOverloadedOperator() &&<br>
+ Method1->isStatic() == Method2->isStatic() &&<br>
+ Method1->isConst() == Method2->isConst() &&<br>
+ Method1->isVolatile() == Method2->isVolatile() &&<br>
+ Method1->isVirtual() == Method2->isVirtual() &&<br>
+ Method1->isPure() == Method2->isPure() &&<br>
+ Method1->isDefaulted() == Method2->isDefaulted() &&<br>
+ Method1->isDeleted() == Method2->isDeleted();<br>
+ if (!PropertiesEqual)<br>
+ return false;<br>
+ // FIXME: Check for 'final'.<br>
+<br>
+ if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {<br>
+ auto *Constructor2 = cast<CXXConstructorDecl>(Method2);<br>
+ if (Constructor1->isExplicit() != Constructor2->isExplicit())<br>
+ return false;<br>
+ }<br>
+<br>
+ if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {<br>
+ auto *Conversion2 = cast<CXXConversionDecl>(Method2);<br>
+ if (Conversion1->isExplicit() != Conversion2->isExplicit())<br>
+ return false;<br>
+ if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),<br>
+ Conversion2->getConversionType()))<br>
+ return false;<br>
+ }<br>
+<br>
+ const IdentifierInfo *Name1 = Method1->getIdentifier();<br>
+ const IdentifierInfo *Name2 = Method2->getIdentifier();<br>
+ if (!::IsStructurallyEquivalent(Name1, Name2)) {<br>
+ return false;<br>
+ // TODO: Names do not match, add warning like at check for FieldDecl.<br>
+ }<br>
+<br>
+ // Check the prototypes.<br>
+ if (!::IsStructurallyEquivalent(Context,<br>
+ Method1->getType(), Method2->getType()))<br>
+ return false;<br>
+<br>
+ return true;<br>
+}<br>
+<br>
/// Determine structural equivalence of two records.<br>
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,<br>
RecordDecl *D1, RecordDecl *D2) {<br>
@@ -1443,6 +1507,14 @@ bool StructuralEquivalenceContext::Finis<br>
Equivalent = false;<br>
} else {<br>
// Kind mismatch.<br>
+ Equivalent = false;<br>
+ }<br>
+ } else if (auto *MD1 = dyn_cast<CXXMethodDecl>(D1)) {<br>
+ if (auto *MD2 = dyn_cast<CXXMethodDecl>(D2)) {<br>
+ if (!::IsStructurallyEquivalent(*this, MD1, MD2))<br>
+ Equivalent = false;<br>
+ } else {<br>
+ // Kind mismatch.<br>
Equivalent = false;<br>
}<br>
} else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) {<br>
<br>
Modified: cfe/trunk/unittests/AST/ASTImporterTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterTest.cpp?rev=336776&r1=336775&r2=336776&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterTest.cpp?rev=336776&r1=336775&r2=336776&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/unittests/AST/ASTImporterTest.cpp (original)<br>
+++ cfe/trunk/unittests/AST/ASTImporterTest.cpp Wed Jul 11 02:37:24 2018<br>
@@ -2243,6 +2243,132 @@ TEST_P(ImportExpr, UnresolvedMemberExpr)<br>
compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));<br>
}<br>
<br>
+TEST_P(ASTImporterTestBase, ImportOfEquivalentRecord) {<br>
+ Decl *ToR1;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { };", Lang_CXX, "input0.cc");<br>
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(<br>
+ FromTU, cxxRecordDecl(hasName("A")));<br>
+<br>
+ ToR1 = Import(FromR, Lang_CXX);<br>
+ }<br>
+<br>
+ Decl *ToR2;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { };", Lang_CXX, "input1.cc");<br>
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(<br>
+ FromTU, cxxRecordDecl(hasName("A")));<br>
+<br>
+ ToR2 = Import(FromR, Lang_CXX);<br>
+ }<br>
+ <br>
+ EXPECT_EQ(ToR1, ToR2);<br>
+}<br>
+<br>
+TEST_P(ASTImporterTestBase, ImportOfNonEquivalentRecord) {<br>
+ Decl *ToR1;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { int x; };", Lang_CXX, "input0.cc");<br>
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(<br>
+ FromTU, cxxRecordDecl(hasName("A")));<br>
+ ToR1 = Import(FromR, Lang_CXX);<br>
+ }<br>
+ Decl *ToR2;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { unsigned x; };", Lang_CXX, "input1.cc");<br>
+ auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(<br>
+ FromTU, cxxRecordDecl(hasName("A")));<br>
+ ToR2 = Import(FromR, Lang_CXX);<br>
+ }<br>
+ EXPECT_NE(ToR1, ToR2);<br>
+}<br>
+<br>
+TEST_P(ASTImporterTestBase, ImportOfEquivalentField) {<br>
+ Decl *ToF1;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { int x; };", Lang_CXX, "input0.cc");<br>
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(<br>
+ FromTU, fieldDecl(hasName("x")));<br>
+ ToF1 = Import(FromF, Lang_CXX);<br>
+ }<br>
+ Decl *ToF2;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { int x; };", Lang_CXX, "input1.cc");<br>
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(<br>
+ FromTU, fieldDecl(hasName("x")));<br>
+ ToF2 = Import(FromF, Lang_CXX);<br>
+ }<br>
+ EXPECT_EQ(ToF1, ToF2);<br>
+}<br>
+<br>
+TEST_P(ASTImporterTestBase, ImportOfNonEquivalentField) {<br>
+ Decl *ToF1;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { int x; };", Lang_CXX, "input0.cc");<br>
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(<br>
+ FromTU, fieldDecl(hasName("x")));<br>
+ ToF1 = Import(FromF, Lang_CXX);<br>
+ }<br>
+ Decl *ToF2;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { unsigned x; };", Lang_CXX, "input1.cc");<br>
+ auto *FromF = FirstDeclMatcher<FieldDecl>().match(<br>
+ FromTU, fieldDecl(hasName("x")));<br>
+ ToF2 = Import(FromF, Lang_CXX);<br>
+ }<br>
+ EXPECT_NE(ToF1, ToF2);<br>
+}<br>
+<br>
+TEST_P(ASTImporterTestBase, ImportOfEquivalentMethod) {<br>
+ Decl *ToM1;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { void x(); }; void A::x() { }", Lang_CXX, "input0.cc");<br>
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(<br>
+ FromTU, functionDecl(hasName("x"), isDefinition()));<br>
+ ToM1 = Import(FromM, Lang_CXX);<br>
+ }<br>
+ Decl *ToM2;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { void x(); }; void A::x() { }", Lang_CXX, "input1.cc");<br>
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(<br>
+ FromTU, functionDecl(hasName("x"), isDefinition()));<br>
+ ToM2 = Import(FromM, Lang_CXX);<br>
+ }<br>
+ EXPECT_EQ(ToM1, ToM2);<br>
+}<br>
+<br>
+TEST_P(ASTImporterTestBase, ImportOfNonEquivalentMethod) {<br>
+ Decl *ToM1;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { void x(); }; void A::x() { }",<br>
+ Lang_CXX, "input0.cc");<br>
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(<br>
+ FromTU, functionDecl(hasName("x"), isDefinition()));<br>
+ ToM1 = Import(FromM, Lang_CXX);<br>
+ }<br>
+ Decl *ToM2;<br>
+ {<br>
+ Decl *FromTU = getTuDecl(<br>
+ "struct A { void x() const; }; void A::x() const { }",<br>
+ Lang_CXX, "input1.cc");<br>
+ auto *FromM = FirstDeclMatcher<FunctionDecl>().match(<br>
+ FromTU, functionDecl(hasName("x"), isDefinition()));<br>
+ ToM2 = Import(FromM, Lang_CXX);<br>
+ }<br>
+ EXPECT_NE(ToM1, ToM2);<br>
+}<br>
+<br>
struct DeclContextTest : ASTImporterTestBase {};<br>
<br>
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {<br>
<br>
Modified: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp?rev=336776&r1=336775&r2=336776&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp?rev=336776&r1=336775&r2=336776&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp (original)<br>
+++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Wed Jul 11 02:37:24 2018<br>
@@ -18,13 +18,13 @@ struct StructuralEquivalenceTest : ::tes<br>
std::unique_ptr<ASTUnit> AST0, AST1;<br>
std::string Code0, Code1; // Buffers for SourceManager<br>
<br>
- // Get a pair of Decl pointers to the synthetised declarations from the given<br>
- // code snipets. By default we search for the unique Decl with name 'foo' in<br>
- // both snippets.<br>
- std::tuple<NamedDecl *, NamedDecl *><br>
- makeNamedDecls(const std::string &SrcCode0, const std::string &SrcCode1,<br>
- Language Lang, const char *const Identifier = "foo") {<br>
-<br>
+ // Get a pair of node pointers into the synthesized AST from the given code<br>
+ // snippets. To determine the returned node, a separate matcher is specified<br>
+ // for both snippets. The first matching node is returned.<br>
+ template <typename NodeType, typename MatcherType><br>
+ std::tuple<NodeType *, NodeType *> makeDecls(<br>
+ const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,<br>
+ const MatcherType &Matcher0, const MatcherType &Matcher1) {<br>
this->Code0 = SrcCode0;<br>
this->Code1 = SrcCode1;<br>
ArgVector Args = getBasicRunOptionsForLanguage(Lang);<br>
@@ -34,30 +34,34 @@ struct StructuralEquivalenceTest : ::tes<br>
AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);<br>
AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);<br>
<br>
- ASTContext &Ctx0 = AST0->getASTContext(), &Ctx1 = AST1->getASTContext();<br>
+ NodeType *D0 = FirstDeclMatcher<NodeType>().match(<br>
+ AST0->getASTContext().getTranslationUnitDecl(), Matcher0);<br>
+ NodeType *D1 = FirstDeclMatcher<NodeType>().match(<br>
+ AST1->getASTContext().getTranslationUnitDecl(), Matcher1);<br>
<br>
- auto getDecl = [](ASTContext &Ctx, const std::string &Name) -> NamedDecl * {<br>
- IdentifierInfo *SearchedII = &Ctx.Idents.get(Name);<br>
- assert(SearchedII && "Declaration with the identifier "<br>
- "should be specified in test!");<br>
- DeclarationName SearchDeclName(SearchedII);<br>
- SmallVector<NamedDecl *, 4> FoundDecls;<br>
- Ctx.getTranslationUnitDecl()->localUncachedLookup(SearchDeclName,<br>
- FoundDecls);<br>
-<br>
- // We should find one Decl but one only.<br>
- assert(FoundDecls.size() == 1);<br>
-<br>
- return FoundDecls[0];<br>
- };<br>
-<br>
- NamedDecl *D0 = getDecl(Ctx0, Identifier);<br>
- NamedDecl *D1 = getDecl(Ctx1, Identifier);<br>
- assert(D0);<br>
- assert(D1);<br>
return std::make_tuple(D0, D1);<br>
}<br>
<br>
+ // Get a pair of node pointers into the synthesized AST from the given code<br>
+ // snippets. The same matcher is used for both snippets.<br>
+ template <typename NodeType, typename MatcherType><br>
+ std::tuple<NodeType *, NodeType *> makeDecls(<br>
+ const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,<br>
+ const MatcherType &AMatcher) {<br>
+ return makeDecls<NodeType, MatcherType>(<br>
+ SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);<br>
+ }<br>
+<br>
+ // Get a pair of Decl pointers to the synthesized declarations from the given<br>
+ // code snippets. We search for the first NamedDecl with given name in both<br>
+ // snippets.<br>
+ std::tuple<NamedDecl *, NamedDecl *> makeNamedDecls(<br>
+ const std::string &SrcCode0, const std::string &SrcCode1,<br>
+ Language Lang, const char *const Identifier = "foo") {<br>
+ auto Matcher = namedDecl(hasName(Identifier));<br>
+ return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);<br>
+ }<br>
+<br>
bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) {<br>
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;<br>
StructuralEquivalenceContext Ctx(D0->getASTContext(), D1->getASTContext(),<br>
@@ -110,35 +114,29 @@ TEST_F(StructuralEquivalenceTest, CharVs<br>
}<br>
<br>
TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {<br>
- auto Decls = makeNamedDecls(<br>
- "template <class T> struct foo; template<> struct foo<int>{};",<br>
- "template <class T> struct foo; template<> struct foo<signed int>{};",<br>
- Lang_CXX);<br>
- ClassTemplateSpecializationDecl *Spec0 =<br>
- *cast<ClassTemplateDecl>(get<0>(Decls))->spec_begin();<br>
- ClassTemplateSpecializationDecl *Spec1 =<br>
- *cast<ClassTemplateDecl>(get<1>(Decls))->spec_begin();<br>
- ASSERT_TRUE(Spec0 != nullptr);<br>
- ASSERT_TRUE(Spec1 != nullptr);<br>
+ auto Decls = makeDecls<ClassTemplateSpecializationDecl>(<br>
+ R"(template <class T> struct foo; template<> struct foo<int>{};)",<br>
+ R"(template <class T> struct foo; template<> struct foo<signed int>{};)",<br>
+ Lang_CXX,<br>
+ classTemplateSpecializationDecl());<br>
+ auto Spec0 = get<0>(Decls);<br>
+ auto Spec1 = get<1>(Decls);<br>
EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));<br>
}<br>
<br>
TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {<br>
- auto Decls = makeNamedDecls(<br>
- "template <class T> struct foo; template<> struct foo<char>{};",<br>
- "template <class T> struct foo; template<> struct foo<signed char>{};",<br>
- Lang_CXX);<br>
- ClassTemplateSpecializationDecl *Spec0 =<br>
- *cast<ClassTemplateDecl>(get<0>(Decls))->spec_begin();<br>
- ClassTemplateSpecializationDecl *Spec1 =<br>
- *cast<ClassTemplateDecl>(get<1>(Decls))->spec_begin();<br>
- ASSERT_TRUE(Spec0 != nullptr);<br>
- ASSERT_TRUE(Spec1 != nullptr);<br>
+ auto Decls = makeDecls<ClassTemplateSpecializationDecl>(<br>
+ R"(template <class T> struct foo; template<> struct foo<char>{};)",<br>
+ R"(template <class T> struct foo; template<> struct foo<signed char>{};)",<br>
+ Lang_CXX,<br>
+ classTemplateSpecializationDecl());<br>
+ auto Spec0 = get<0>(Decls);<br>
+ auto Spec1 = get<1>(Decls);<br>
EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));<br>
}<br>
<br>
TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {<br>
- auto Decls = makeNamedDecls(<br>
+ auto Decls = makeDecls<ClassTemplateSpecializationDecl>(<br>
R"(<br>
struct true_type{};<br>
template <class T> struct foo;<br>
@@ -149,14 +147,9 @@ TEST_F(StructuralEquivalenceTest, CharVs<br>
template <class T> struct foo;<br>
template<> struct foo<signed char> : true_type {};<br>
)",<br>
- Lang_CXX);<br>
- ClassTemplateSpecializationDecl *Spec0 =<br>
- *cast<ClassTemplateDecl>(get<0>(Decls))->spec_begin();<br>
- ClassTemplateSpecializationDecl *Spec1 =<br>
- *cast<ClassTemplateDecl>(get<1>(Decls))->spec_begin();<br>
- ASSERT_TRUE(Spec0 != nullptr);<br>
- ASSERT_TRUE(Spec1 != nullptr);<br>
- EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));<br>
+ Lang_CXX,<br>
+ classTemplateSpecializationDecl());<br>
+ EXPECT_FALSE(testStructuralMatch(Decls));<br>
}<br>
<br>
// This test is disabled for now.<br>
@@ -203,5 +196,350 @@ TEST_F(StructuralEquivalenceTest, WrongO<br>
EXPECT_FALSE(testStructuralMatch(Decls));<br>
}<br>
<br>
+struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {<br>
+};<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {<br>
+ auto t = makeNamedDecls("void foo(int&);",<br>
+ "void foo(const int&);", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {<br>
+ auto t = makeNamedDecls("void foo(int);",<br>
+ "void foo(const int);", Lang_CXX);<br>
+ EXPECT_TRUE(testStructuralMatch(t));<br>
+ // consider this OK<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, Throw) {<br>
+ auto t = makeNamedDecls("void foo();",<br>
+ "void foo() throw();", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {<br>
+ auto t = makeNamedDecls("void foo();",<br>
+ "void foo() noexcept;", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {<br>
+ auto t = makeNamedDecls("void foo() throw();",<br>
+ "void foo() noexcept;", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {<br>
+ auto t = makeNamedDecls("void foo() throw();",<br>
+ "void foo() noexcept(false);", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {<br>
+ auto t = makeNamedDecls("void foo() throw();",<br>
+ "void foo() noexcept(true);", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {<br>
+ // The expression is not checked yet.<br>
+ auto t = makeNamedDecls("void foo() noexcept(false);",<br>
+ "void foo() noexcept(true);", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {<br>
+ auto t = makeNamedDecls("void foo() noexcept(false);",<br>
+ "void foo() noexcept(false);", Lang_CXX11);<br>
+ EXPECT_TRUE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {<br>
+ auto t = makeNamedDecls("void foo() noexcept;",<br>
+ "void foo() noexcept(false);", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {<br>
+ auto t = makeNamedDecls("void foo() noexcept;",<br>
+ "void foo() noexcept(true);", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {<br>
+ auto t = makeNamedDecls("char foo();",<br>
+ "int foo();", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {<br>
+ auto t = makeNamedDecls("char foo();",<br>
+ "const char foo();", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {<br>
+ auto t = makeNamedDecls("char &foo();",<br>
+ "char &&foo();", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {<br>
+ auto t = makeNamedDecls("void foo(int);",<br>
+ "void foo(int, int);", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ParamType) {<br>
+ auto t = makeNamedDecls("void foo(int);",<br>
+ "void foo(char);", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ParamName) {<br>
+ auto t = makeNamedDecls("void foo(int a);",<br>
+ "void foo(int b);", Lang_CXX);<br>
+ EXPECT_TRUE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, Variadic) {<br>
+ auto t = makeNamedDecls("void foo(int x...);",<br>
+ "void foo(int x);", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {<br>
+ auto t = makeNamedDecls("void foo(int *);",<br>
+ "void foo(int);", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {<br>
+ auto t = makeNamedDecls(<br>
+ "void ((foo))();",<br>
+ "void foo();",<br>
+ Lang_CXX);<br>
+ EXPECT_TRUE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {<br>
+ auto t = makeNamedDecls(<br>
+ "void (foo)() throw(int);",<br>
+ "void (foo)() noexcept;",<br>
+ Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {<br>
+ auto t = makeNamedDecls(<br>
+ "struct A { void (foo)() const; };",<br>
+ "struct A { void (foo)(); };",<br>
+ Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {<br>
+};<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {<br>
+ auto t = makeDecls<CXXMethodDecl>(<br>
+ "struct X { void foo(); };",<br>
+ "struct X { virtual void foo(); };", Lang_CXX,<br>
+ cxxMethodDecl(hasName("foo")));<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {<br>
+ auto t = makeNamedDecls("struct X { virtual void foo(); };",<br>
+ "struct X { virtual void foo() = 0; };", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {<br>
+ // The final-ness is not checked yet.<br>
+ auto t = makeNamedDecls("struct X { virtual void foo(); };",<br>
+ "struct X { virtual void foo() final; };", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Const) {<br>
+ auto t = makeNamedDecls("struct X { void foo(); };",<br>
+ "struct X { void foo() const; };", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Static) {<br>
+ auto t = makeNamedDecls("struct X { void foo(); };",<br>
+ "struct X { static void foo(); };", Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {<br>
+ auto t = makeNamedDecls("struct X { void foo(); };",<br>
+ "struct X { void foo() &&; };", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {<br>
+ auto t = makeNamedDecls("struct X { void foo() &; };",<br>
+ "struct X { void foo() &&; };", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {<br>
+ auto t = makeDecls<CXXMethodDecl>(<br>
+ "struct X { public: void foo(); };",<br>
+ "struct X { private: void foo(); };", Lang_CXX,<br>
+ cxxMethodDecl(hasName("foo")));<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {<br>
+ auto t = makeNamedDecls("struct X { void foo(); };",<br>
+ "struct X { void foo() = delete; };", Lang_CXX11);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {<br>
+ auto t = makeDecls<FunctionDecl>(<br>
+ "void foo();", "struct foo { foo(); };", Lang_CXX,<br>
+ functionDecl(), cxxConstructorDecl());<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {<br>
+ auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",<br>
+ "struct X { X(int); };", Lang_CXX,<br>
+ cxxConstructorDecl());<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {<br>
+ auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",<br>
+ "struct X { explicit X(int); };",<br>
+ Lang_CXX11,<br>
+ cxxConstructorDecl());<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {<br>
+ auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",<br>
+ "struct X { X() = default; };",<br>
+ Lang_CXX11,<br>
+ cxxConstructorDecl());<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {<br>
+ auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",<br>
+ "struct X { operator char(); };",<br>
+ Lang_CXX11,<br>
+ cxxConversionDecl());<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {<br>
+ auto t = makeDecls<FunctionDecl>(<br>
+ "struct X { int operator +(int); };",<br>
+ "struct X { int operator -(int); };", Lang_CXX,<br>
+ functionDecl(hasOverloadedOperatorName("+")),<br>
+ functionDecl(hasOverloadedOperatorName("-")));<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {<br>
+ auto t = makeDecls<FunctionDecl>(<br>
+ "struct X { virtual void f(); }; void X::f() { }",<br>
+ "struct X { virtual void f() { }; };",<br>
+ Lang_CXX,<br>
+ functionDecl(allOf(hasName("f"), isDefinition())));<br>
+ EXPECT_TRUE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {<br>
+ auto t = makeDecls<FunctionDecl>(<br>
+ "struct X { virtual void f(); }; void X::f() { }",<br>
+ "struct X { void f(); }; void X::f() { }",<br>
+ Lang_CXX,<br>
+ functionDecl(allOf(hasName("f"), isDefinition())));<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {<br>
+};<br>
+<br>
+TEST_F(StructuralEquivalenceRecordTest, Name) {<br>
+ auto t = makeDecls<CXXRecordDecl>(<br>
+ "struct A{ };",<br>
+ "struct B{ };",<br>
+ Lang_CXX,<br>
+ cxxRecordDecl());<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceRecordTest, Fields) {<br>
+ auto t = makeNamedDecls(<br>
+ "struct foo{ int x; };",<br>
+ "struct foo{ char x; };",<br>
+ Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {<br>
+ // Currently, methods of a class are not checked at class equivalence.<br>
+ auto t = makeNamedDecls(<br>
+ "struct foo{ int x(); };",<br>
+ "struct foo{ char x(); };",<br>
+ Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceRecordTest, Bases) {<br>
+ auto t = makeNamedDecls(<br>
+ "struct A{ }; struct foo: A { };",<br>
+ "struct B{ }; struct foo: B { };",<br>
+ Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {<br>
+ auto t = makeNamedDecls(<br>
+ "struct A{ }; struct foo: A { };",<br>
+ "struct A{ }; struct foo: virtual A { };",<br>
+ Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {<br>
+ // Access specifier in inheritance is not checked yet.<br>
+ auto t = makeNamedDecls(<br>
+ "struct A{ }; struct foo: public A { };",<br>
+ "struct A{ }; struct foo: private A { };",<br>
+ Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceRecordTest, Match) {<br>
+ auto Code = R"(<br>
+ struct A{ };<br>
+ struct B{ };<br>
+ struct foo: A, virtual B {<br>
+ void x();<br>
+ int a;<br>
+ };<br>
+ )";<br>
+ auto t = makeNamedDecls(Code, Code, Lang_CXX);<br>
+ EXPECT_TRUE(testStructuralMatch(t));<br>
+}<br>
+<br>
+TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {<br>
+ auto t = makeNamedDecls(<br>
+ "struct A{ }; struct B{ }; void foo(A a, A b);",<br>
+ "struct A{ }; struct B{ }; void foo(A a, B b);",<br>
+ Lang_CXX);<br>
+ EXPECT_FALSE(testStructuralMatch(t));<br>
+}<br>
+<br>
} // end namespace ast_matchers<br>
} // end namespace clang<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>
</blockquote></div>