From: Fariborz Jahanian Date: Tue, 16 Jul 2013 00:20:21 +0000 (+0000) Subject: ObjC migrator: build conforming interface X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8c355831ac3c9e8c12b23ca69b7587dcbd0439ef;p=clang ObjC migrator: build conforming interface declaration (not yet used). wip. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186369 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Edit/Rewriters.h b/include/clang/Edit/Rewriters.h index cfb59dfa32..d7718c540b 100644 --- a/include/clang/Edit/Rewriters.h +++ b/include/clang/Edit/Rewriters.h @@ -9,10 +9,13 @@ #ifndef LLVM_CLANG_EDIT_REWRITERS_H #define LLVM_CLANG_EDIT_REWRITERS_H +#include "llvm/ADT/SmallVector.h" namespace clang { class ObjCMessageExpr; class ObjCMethodDecl; + class ObjCInterfaceDecl; + class ObjCProtocolDecl; class NSAPI; class ParentMap; @@ -29,6 +32,9 @@ bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, bool rewriteToObjCProperty(const ObjCMethodDecl *Getter, const ObjCMethodDecl *Setter, const NSAPI &NS, Commit &commit); +bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, + llvm::SmallVectorImpl &Protocols, + const NSAPI &NS, Commit &commit); bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit); diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 18919faa9a..dd21026458 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -250,6 +250,8 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional) continue; DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName()); + if (R.size() == 0) + return false; for (unsigned I = 0, N = R.size(); I != N; ++I) { if (ObjCPropertyDecl *ClassProperty = dyn_cast(R[0])) { if (ClassProperty->getPropertyAttributes() @@ -263,14 +265,20 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, // 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()) + if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) { + if (PDecl->meth_begin() == PDecl->meth_end()) + return false; for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(), MEnd = PDecl->meth_end(); M != MEnd; ++M) { ObjCMethodDecl *MD = (*M); + if (MD->isImplicit()) + continue; if (MD->getImplementationControl() == ObjCMethodDecl::Optional) continue; bool match = false; DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName()); + if (R.size() == 0) + return false; for (unsigned I = 0, N = R.size(); I != N; ++I) if (ObjCMethodDecl *ImpMD = dyn_cast(R[0])) if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) { @@ -280,6 +288,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, if (!match) return false; } + } return true; } @@ -312,6 +321,12 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl, PotentialImplicitProtocols[i])) ConformingProtocols.push_back(PotentialImplicitProtocols[i]); + + if (ConformingProtocols.empty()) + return; + edit::Commit commit(*Editor); + edit::rewriteToObjCInterfaceDecl(IDecl, ConformingProtocols, *NSAPIObj, commit); + Editor->commit(commit); } namespace { diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp index 8d24003d94..fd9c16ee6a 100644 --- a/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -402,6 +402,38 @@ bool edit::rewriteToObjCProperty(const ObjCMethodDecl *Getter, return true; } +bool edit::rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, + llvm::SmallVectorImpl &ConformingProtocols, + const NSAPI &NS, Commit &commit) { + const ObjCList &Protocols = IDecl->getReferencedProtocols(); + + // ASTContext &Context = NS.getASTContext(); + std::string ClassString = "@interface "; + ClassString += IDecl->getNameAsString(); + + if (IDecl->getSuperClass()) { + ClassString += " : "; + ClassString += IDecl->getSuperClass()->getNameAsString(); + } + if (Protocols.empty()) + ClassString += '<'; + + for (ObjCList::iterator I = Protocols.begin(), + E = Protocols.end(); I != E; ++I) { + ClassString += (I == Protocols.begin() ? '<' : ','); + ClassString += (*I)->getNameAsString(); + } + if (!Protocols.empty()) + ClassString += ','; + for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { + ClassString += ConformingProtocols[i]->getNameAsString(); + if (i != (e-1)) + ClassString += ','; + } + ClassString += "> "; + return true; +} + /// \brief Returns true if the immediate message arguments of \c Msg should not /// be rewritten because it will interfere with the rewrite of the parent /// message expression. e.g.