From ad4aaf11897cc5e9d443b0a80114daacf385f6df Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Mon, 15 Jul 2013 21:22:08 +0000 Subject: [PATCH] ObjC migrator: finding conforming protocol candidates for each class. wip. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186349 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 3 +++ lib/ARCMigrate/ObjCMT.cpp | 46 ++++++++++++++++++++++++++++++++-- lib/AST/ASTContext.cpp | 32 +++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f0b0e41bd0..a686f3378f 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1717,6 +1717,9 @@ public: getCanonicalType(T2).getTypePtr(); } + bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, + const ObjCMethodDecl *MethodImp); + bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); /// \brief Retrieves the "canonical" nested name specifier for a diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 0153166860..18919faa9a 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -238,8 +238,50 @@ void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx, static bool ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, const ObjCImplementationDecl *ImpDecl, + const ObjCInterfaceDecl *IDecl, ObjCProtocolDecl *Protocol) { - return false; + // In auto-synthesis, protocol properties are not synthesized. So, + // a conforming protocol must have its required properties declared + // in class interface. + if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Property = *P; + if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional) + continue; + DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName()); + for (unsigned I = 0, N = R.size(); I != N; ++I) { + if (ObjCPropertyDecl *ClassProperty = dyn_cast(R[0])) { + if (ClassProperty->getPropertyAttributes() + != Property->getPropertyAttributes()) + return false; + if (!Ctx.hasSameType(ClassProperty->getType(), Property->getType())) + return false; + } + } + } + // At this point, all required properties in this protocol conform to those + // declared in the class. + // Check that class implements the required methods of the protocol too. + if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) + for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(), + MEnd = PDecl->meth_end(); M != MEnd; ++M) { + ObjCMethodDecl *MD = (*M); + if (MD->getImplementationControl() == ObjCMethodDecl::Optional) + continue; + bool match = false; + DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName()); + for (unsigned I = 0, N = R.size(); I != N; ++I) + if (ObjCMethodDecl *ImpMD = dyn_cast(R[0])) + if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) { + match = true; + break; + } + if (!match) + return false; + } + + return true; } void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, @@ -267,7 +309,7 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, // methods and properties, then this class conforms to this protocol. llvm::SmallVector ConformingProtocols; for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++) - if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, + if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl, PotentialImplicitProtocols[i])) ConformingProtocols.push_back(PotentialImplicitProtocols[i]); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8984c3c96d..8a252f8e73 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -8129,3 +8129,35 @@ ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) { } return I->second; } + +bool +ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, + const ObjCMethodDecl *MethodImpl) { + // No point trying to match an unavailable/deprecated mothod. + if (MethodDecl->hasAttr() + || MethodDecl->hasAttr()) + return false; + if (MethodDecl->getObjCDeclQualifier() != + MethodImpl->getObjCDeclQualifier()) + return false; + if (!hasSameType(MethodDecl->getResultType(), + MethodImpl->getResultType())) + return false; + + if (MethodDecl->param_size() != MethodImpl->param_size()) + return false; + + for (ObjCMethodDecl::param_const_iterator IM = MethodImpl->param_begin(), + IF = MethodDecl->param_begin(), EM = MethodImpl->param_end(), + EF = MethodDecl->param_end(); + IM != EM && IF != EF; ++IM, ++IF) { + const ParmVarDecl *DeclVar = (*IF); + const ParmVarDecl *ImplVar = (*IM); + if (ImplVar->getObjCDeclQualifier() != DeclVar->getObjCDeclQualifier()) + return false; + if (!hasSameType(DeclVar->getType(), ImplVar->getType())) + return false; + } + return (MethodDecl->isVariadic() == MethodImpl->isVariadic()); + +} -- 2.40.0