diff options
author | Balazs Keri <1.int32@gmail.com> | 2018-07-11 09:37:24 +0000 |
---|---|---|
committer | Balazs Keri <1.int32@gmail.com> | 2018-07-11 09:37:24 +0000 |
commit | c7797c4bab5d181e7fd9ae01ae72bf2ab34a5936 (patch) | |
tree | 5c18600858e136674f92a9975cd98883b86755da /clang/lib/AST/ASTStructuralEquivalence.cpp | |
parent | e21cfa7e7f9851ff56f8bd4b3166618a59f31eab (diff) | |
download | bcm5719-llvm-c7797c4bab5d181e7fd9ae01ae72bf2ab34a5936.tar.gz bcm5719-llvm-c7797c4bab5d181e7fd9ae01ae72bf2ab34a5936.zip |
[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
llvm-svn: 336776
Diffstat (limited to 'clang/lib/AST/ASTStructuralEquivalence.cpp')
-rw-r--r-- | clang/lib/AST/ASTStructuralEquivalence.cpp | 94 |
1 files changed, 83 insertions, 11 deletions
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index b543991873a..367755ffd03 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -250,6 +250,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (T1.isNull() || T2.isNull()) return T1.isNull() && T2.isNull(); + QualType OrigT1 = T1; + QualType OrigT2 = T2; + if (!Context.StrictTypeSpelling) { // We aren't being strict about token-to-token equivalence of types, // so map down to the canonical type. @@ -422,6 +425,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::FunctionProto: { const auto *Proto1 = cast<FunctionProtoType>(T1); const auto *Proto2 = cast<FunctionProtoType>(T2); + if (Proto1->getNumParams() != Proto2->getNumParams()) return false; for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) { @@ -431,23 +435,33 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } if (Proto1->isVariadic() != Proto2->isVariadic()) return false; - if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) + + if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) return false; - if (Proto1->getExceptionSpecType() == EST_Dynamic) { - if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + + // Check exceptions, this information is lost in canonical type. + const auto *OrigProto1 = + cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx)); + const auto *OrigProto2 = + cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx)); + auto Spec1 = OrigProto1->getExceptionSpecType(); + auto Spec2 = OrigProto2->getExceptionSpecType(); + + if (Spec1 != Spec2) + return false; + if (Spec1 == EST_Dynamic) { + if (OrigProto1->getNumExceptions() != OrigProto2->getNumExceptions()) return false; - for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I), - Proto2->getExceptionType(I))) + for (unsigned I = 0, N = OrigProto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, OrigProto1->getExceptionType(I), + OrigProto2->getExceptionType(I))) return false; } - } else if (isComputedNoexcept(Proto1->getExceptionSpecType())) { - if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(), - Proto2->getNoexceptExpr())) + } else if (isComputedNoexcept(Spec1)) { + if (!IsStructurallyEquivalent(Context, OrigProto1->getNoexceptExpr(), + OrigProto2->getNoexceptExpr())) return false; } - if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) - return false; // Fall through to check the bits common with FunctionNoProtoType. LLVM_FALLTHROUGH; @@ -830,6 +844,56 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// Determine structural equivalence of two methodss. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + CXXMethodDecl *Method1, + CXXMethodDecl *Method2) { + bool PropertiesEqual = + Method1->getDeclKind() == Method2->getDeclKind() && + Method1->getRefQualifier() == Method2->getRefQualifier() && + Method1->getAccess() == Method2->getAccess() && + Method1->getOverloadedOperator() == Method2->getOverloadedOperator() && + Method1->isStatic() == Method2->isStatic() && + Method1->isConst() == Method2->isConst() && + Method1->isVolatile() == Method2->isVolatile() && + Method1->isVirtual() == Method2->isVirtual() && + Method1->isPure() == Method2->isPure() && + Method1->isDefaulted() == Method2->isDefaulted() && + Method1->isDeleted() == Method2->isDeleted(); + if (!PropertiesEqual) + return false; + // FIXME: Check for 'final'. + + if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) { + auto *Constructor2 = cast<CXXConstructorDecl>(Method2); + if (Constructor1->isExplicit() != Constructor2->isExplicit()) + return false; + } + + if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) { + auto *Conversion2 = cast<CXXConversionDecl>(Method2); + if (Conversion1->isExplicit() != Conversion2->isExplicit()) + return false; + if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(), + Conversion2->getConversionType())) + return false; + } + + const IdentifierInfo *Name1 = Method1->getIdentifier(); + const IdentifierInfo *Name2 = Method2->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2)) { + return false; + // TODO: Names do not match, add warning like at check for FieldDecl. + } + + // Check the prototypes. + if (!::IsStructurallyEquivalent(Context, + Method1->getType(), Method2->getType())) + return false; + + return true; +} + /// Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { @@ -1445,6 +1509,14 @@ bool StructuralEquivalenceContext::Finish() { // Kind mismatch. Equivalent = false; } + } else if (auto *MD1 = dyn_cast<CXXMethodDecl>(D1)) { + if (auto *MD2 = dyn_cast<CXXMethodDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, MD1, MD2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) { if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) { if (!::IsStructurallyEquivalent(FD1->getIdentifier(), |