diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/ARCMigrate/ObjCMT.cpp | 46 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 32 |
2 files changed, 76 insertions, 2 deletions
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index 01531668603..18919faa9a4 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/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<ObjCPropertyDecl>(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<ObjCMethodDecl>(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<ObjCProtocolDecl*, 8> 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/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8984c3c96dd..8a252f8e73b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/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<UnavailableAttr>() + || MethodDecl->hasAttr<DeprecatedAttr>()) + 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()); + +} |