summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ASTStructuralEquivalence.cpp
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
commitc7797c4bab5d181e7fd9ae01ae72bf2ab34a5936 (patch)
tree5c18600858e136674f92a9975cd98883b86755da /clang/lib/AST/ASTStructuralEquivalence.cpp
parente21cfa7e7f9851ff56f8bd4b3166618a59f31eab (diff)
downloadbcm5719-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.cpp94
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(),
OpenPOWER on IntegriCloud