ObjC migrator: finding conforming protocol

candidates for each class. wip.

llvm-svn: 186349
This commit is contained in:
Fariborz Jahanian 2013-07-15 21:22:08 +00:00
parent 786928dbd2
commit d36150d7ca
3 changed files with 79 additions and 2 deletions

View File

@ -1717,6 +1717,9 @@ public:
getCanonicalType(T2).getTypePtr(); getCanonicalType(T2).getTypePtr();
} }
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
const ObjCMethodDecl *MethodImp);
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
/// \brief Retrieves the "canonical" nested name specifier for a /// \brief Retrieves the "canonical" nested name specifier for a

View File

@ -238,8 +238,50 @@ void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
static bool static bool
ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
const ObjCImplementationDecl *ImpDecl, const ObjCImplementationDecl *ImpDecl,
const ObjCInterfaceDecl *IDecl,
ObjCProtocolDecl *Protocol) { 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, void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
@ -267,7 +309,7 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
// methods and properties, then this class conforms to this protocol. // methods and properties, then this class conforms to this protocol.
llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols; llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++) for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
PotentialImplicitProtocols[i])) PotentialImplicitProtocols[i]))
ConformingProtocols.push_back(PotentialImplicitProtocols[i]); ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
} }

View File

@ -8129,3 +8129,35 @@ ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
} }
return I->second; 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());
}