From 5bd5affe2dd2c7de071970ae89f0c97965188d20 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 16 Jul 2013 00:20:21 +0000 Subject: [PATCH] ObjC migrator: build conforming interface declaration (not yet used). wip. llvm-svn: 186369 --- clang/include/clang/Edit/Rewriters.h | 6 ++++ clang/lib/ARCMigrate/ObjCMT.cpp | 17 ++++++++++- clang/lib/Edit/RewriteObjCFoundationAPI.cpp | 32 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Edit/Rewriters.h b/clang/include/clang/Edit/Rewriters.h index cfb59dfa32c6..d7718c540b4e 100644 --- a/clang/include/clang/Edit/Rewriters.h +++ b/clang/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/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index 18919faa9a4c..dd210264582e 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/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/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index 8d24003d9427..fd9c16ee6a09 100644 --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/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.