Home | History | Annotate | Download | only in ARCMigrate
      1 //===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "Transforms.h"
     11 #include "clang/ARCMigrate/ARCMTActions.h"
     12 #include "clang/AST/ASTConsumer.h"
     13 #include "clang/AST/ASTContext.h"
     14 #include "clang/AST/NSAPI.h"
     15 #include "clang/AST/ParentMap.h"
     16 #include "clang/AST/RecursiveASTVisitor.h"
     17 #include "clang/Basic/FileManager.h"
     18 #include "clang/Edit/Commit.h"
     19 #include "clang/Edit/EditedSource.h"
     20 #include "clang/Edit/EditsReceiver.h"
     21 #include "clang/Edit/Rewriters.h"
     22 #include "clang/Frontend/CompilerInstance.h"
     23 #include "clang/Frontend/MultiplexConsumer.h"
     24 #include "clang/Lex/PPConditionalDirectiveRecord.h"
     25 #include "clang/Lex/Preprocessor.h"
     26 #include "clang/Rewrite/Core/Rewriter.h"
     27 #include "llvm/ADT/SmallString.h"
     28 
     29 using namespace clang;
     30 using namespace arcmt;
     31 
     32 namespace {
     33 
     34 class ObjCMigrateASTConsumer : public ASTConsumer {
     35   void migrateDecl(Decl *D);
     36   void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCInterfaceDecl *D);
     37   void migrateProtocolConformance(ASTContext &Ctx,
     38                                   const ObjCImplementationDecl *ImpDecl);
     39   void migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
     40                      const TypedefDecl *TypedefDcl);
     41   void migrateInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
     42   void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
     43                                  ObjCMethodDecl *OM);
     44   void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
     45                             ObjCMethodDecl *OM,
     46                             ObjCInstanceTypeFamily OIT_Family = OIT_None);
     47 
     48 public:
     49   std::string MigrateDir;
     50   bool MigrateLiterals;
     51   bool MigrateSubscripting;
     52   bool MigrateProperty;
     53   OwningPtr<NSAPI> NSAPIObj;
     54   OwningPtr<edit::EditedSource> Editor;
     55   FileRemapper &Remapper;
     56   FileManager &FileMgr;
     57   const PPConditionalDirectiveRecord *PPRec;
     58   Preprocessor &PP;
     59   bool IsOutputFile;
     60   llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
     61 
     62   ObjCMigrateASTConsumer(StringRef migrateDir,
     63                          bool migrateLiterals,
     64                          bool migrateSubscripting,
     65                          bool migrateProperty,
     66                          FileRemapper &remapper,
     67                          FileManager &fileMgr,
     68                          const PPConditionalDirectiveRecord *PPRec,
     69                          Preprocessor &PP,
     70                          bool isOutputFile = false)
     71   : MigrateDir(migrateDir),
     72     MigrateLiterals(migrateLiterals),
     73     MigrateSubscripting(migrateSubscripting),
     74     MigrateProperty(migrateProperty),
     75     Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
     76     IsOutputFile(isOutputFile) { }
     77 
     78 protected:
     79   virtual void Initialize(ASTContext &Context) {
     80     NSAPIObj.reset(new NSAPI(Context));
     81     Editor.reset(new edit::EditedSource(Context.getSourceManager(),
     82                                         Context.getLangOpts(),
     83                                         PPRec));
     84   }
     85 
     86   virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
     87     for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
     88       migrateDecl(*I);
     89     return true;
     90   }
     91   virtual void HandleInterestingDecl(DeclGroupRef DG) {
     92     // Ignore decls from the PCH.
     93   }
     94   virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
     95     ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
     96   }
     97 
     98   virtual void HandleTranslationUnit(ASTContext &Ctx);
     99 };
    100 
    101 }
    102 
    103 ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
    104                              StringRef migrateDir,
    105                              bool migrateLiterals,
    106                              bool migrateSubscripting,
    107                              bool migrateProperty)
    108   : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
    109     MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
    110     MigrateProperty(migrateProperty),
    111     CompInst(0) {
    112   if (MigrateDir.empty())
    113     MigrateDir = "."; // user current directory if none is given.
    114 }
    115 
    116 ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
    117                                                   StringRef InFile) {
    118   PPConditionalDirectiveRecord *
    119     PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
    120   CompInst->getPreprocessor().addPPCallbacks(PPRec);
    121   ASTConsumer *
    122     WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
    123   ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
    124                                                        MigrateLiterals,
    125                                                        MigrateSubscripting,
    126                                                        MigrateProperty,
    127                                                        Remapper,
    128                                                     CompInst->getFileManager(),
    129                                                        PPRec,
    130                                                        CompInst->getPreprocessor());
    131   ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
    132   return new MultiplexConsumer(Consumers);
    133 }
    134 
    135 bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
    136   Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
    137                         /*ignoreIfFilesChanges=*/true);
    138   CompInst = &CI;
    139   CI.getDiagnostics().setIgnoreAllWarnings(true);
    140   return true;
    141 }
    142 
    143 namespace {
    144 class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
    145   ObjCMigrateASTConsumer &Consumer;
    146   ParentMap &PMap;
    147 
    148 public:
    149   ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
    150     : Consumer(consumer), PMap(PMap) { }
    151 
    152   bool shouldVisitTemplateInstantiations() const { return false; }
    153   bool shouldWalkTypesOfTypeLocs() const { return false; }
    154 
    155   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
    156     if (Consumer.MigrateLiterals) {
    157       edit::Commit commit(*Consumer.Editor);
    158       edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
    159       Consumer.Editor->commit(commit);
    160     }
    161 
    162     if (Consumer.MigrateSubscripting) {
    163       edit::Commit commit(*Consumer.Editor);
    164       edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
    165       Consumer.Editor->commit(commit);
    166     }
    167 
    168     return true;
    169   }
    170 
    171   bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
    172     // Do depth first; we want to rewrite the subexpressions first so that if
    173     // we have to move expressions we will move them already rewritten.
    174     for (Stmt::child_range range = E->children(); range; ++range)
    175       if (!TraverseStmt(*range))
    176         return false;
    177 
    178     return WalkUpFromObjCMessageExpr(E);
    179   }
    180 };
    181 
    182 class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
    183   ObjCMigrateASTConsumer &Consumer;
    184   OwningPtr<ParentMap> PMap;
    185 
    186 public:
    187   BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
    188 
    189   bool shouldVisitTemplateInstantiations() const { return false; }
    190   bool shouldWalkTypesOfTypeLocs() const { return false; }
    191 
    192   bool TraverseStmt(Stmt *S) {
    193     PMap.reset(new ParentMap(S));
    194     ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
    195     return true;
    196   }
    197 };
    198 }
    199 
    200 void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
    201   if (!D)
    202     return;
    203   if (isa<ObjCMethodDecl>(D))
    204     return; // Wait for the ObjC container declaration.
    205 
    206   BodyMigrator(*this).TraverseDecl(D);
    207 }
    208 
    209 static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter,
    210                                   const ObjCMethodDecl *Setter,
    211                                   const NSAPI &NS, edit::Commit &commit) {
    212   ASTContext &Context = NS.getASTContext();
    213   std::string PropertyString = "@property";
    214 
    215   std::string PropertyNameString = Getter->getNameAsString();
    216   StringRef PropertyName(PropertyNameString);
    217   // Short circuit properties that contain the name "delegate" or "dataSource",
    218   // or have exact name "target" to have unsafe_unretained attribute.
    219   if (PropertyName.equals("target") ||
    220       (PropertyName.find("delegate") != StringRef::npos) ||
    221       (PropertyName.find("dataSource") != StringRef::npos))
    222     PropertyString += "(unsafe_unretained)";
    223   else {
    224     const ParmVarDecl *argDecl = *Setter->param_begin();
    225     QualType ArgType = Context.getCanonicalType(argDecl->getType());
    226     Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
    227     bool RetainableObject = ArgType->isObjCRetainableType();
    228     if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
    229       if (const ObjCObjectPointerType *ObjPtrTy =
    230           ArgType->getAs<ObjCObjectPointerType>()) {
    231         ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
    232         if (IDecl &&
    233             IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
    234           PropertyString += "(copy)";
    235         else
    236           PropertyString += "(retain)";
    237       }
    238     } else if (propertyLifetime == Qualifiers::OCL_Weak)
    239       // TODO. More precise determination of 'weak' attribute requires
    240       // looking into setter's implementation for backing weak ivar.
    241       PropertyString += "(weak)";
    242     else if (RetainableObject)
    243       PropertyString += "(retain)";
    244   }
    245 
    246   // strip off any ARC lifetime qualifier.
    247   QualType CanResultTy = Context.getCanonicalType(Getter->getResultType());
    248   if (CanResultTy.getQualifiers().hasObjCLifetime()) {
    249     Qualifiers Qs = CanResultTy.getQualifiers();
    250     Qs.removeObjCLifetime();
    251     CanResultTy = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
    252   }
    253   PropertyString += " ";
    254   PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy());
    255   PropertyString += " ";
    256   PropertyString += PropertyNameString;
    257   commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
    258                                                Getter->getDeclaratorEndLoc()),
    259                  PropertyString);
    260   SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
    261   // Get location past ';'
    262   EndLoc = EndLoc.getLocWithOffset(1);
    263   commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc));
    264   return true;
    265 }
    266 
    267 void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
    268                                                       ObjCInterfaceDecl *D) {
    269   for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
    270        M != MEnd; ++M) {
    271     ObjCMethodDecl *Method = (*M);
    272     if (Method->isPropertyAccessor() ||  Method->param_size() != 0)
    273       continue;
    274     // Is this method candidate to be a getter?
    275     QualType GRT = Method->getResultType();
    276     if (GRT->isVoidType())
    277       continue;
    278     // FIXME. Don't know what todo with attributes, skip for now.
    279     if (Method->hasAttrs())
    280       continue;
    281 
    282     Selector GetterSelector = Method->getSelector();
    283     IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
    284     Selector SetterSelector =
    285       SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
    286                                              PP.getSelectorTable(),
    287                                              getterName);
    288     if (ObjCMethodDecl *SetterMethod = D->lookupMethod(SetterSelector, true)) {
    289       // Is this a valid setter, matching the target getter?
    290       QualType SRT = SetterMethod->getResultType();
    291       if (!SRT->isVoidType())
    292         continue;
    293       const ParmVarDecl *argDecl = *SetterMethod->param_begin();
    294       QualType ArgType = argDecl->getType();
    295       if (!Ctx.hasSameUnqualifiedType(ArgType, GRT) ||
    296           SetterMethod->hasAttrs())
    297           continue;
    298         edit::Commit commit(*Editor);
    299         rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit);
    300         Editor->commit(commit);
    301       }
    302   }
    303 }
    304 
    305 static bool
    306 ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
    307                                       const ObjCImplementationDecl *ImpDecl,
    308                                        const ObjCInterfaceDecl *IDecl,
    309                                       ObjCProtocolDecl *Protocol) {
    310   // In auto-synthesis, protocol properties are not synthesized. So,
    311   // a conforming protocol must have its required properties declared
    312   // in class interface.
    313   bool HasAtleastOneRequiredProperty = false;
    314   if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
    315     for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
    316          E = PDecl->prop_end(); P != E; ++P) {
    317       ObjCPropertyDecl *Property = *P;
    318       if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
    319         continue;
    320       HasAtleastOneRequiredProperty = true;
    321       DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
    322       if (R.size() == 0) {
    323         // Relax the rule and look into class's implementation for a synthesize
    324         // or dynamic declaration. Class is implementing a property coming from
    325         // another protocol. This still makes the target protocol as conforming.
    326         if (!ImpDecl->FindPropertyImplDecl(
    327                                   Property->getDeclName().getAsIdentifierInfo()))
    328           return false;
    329       }
    330       else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
    331           if ((ClassProperty->getPropertyAttributes()
    332               != Property->getPropertyAttributes()) ||
    333               !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
    334             return false;
    335       }
    336       else
    337         return false;
    338     }
    339 
    340   // At this point, all required properties in this protocol conform to those
    341   // declared in the class.
    342   // Check that class implements the required methods of the protocol too.
    343   bool HasAtleastOneRequiredMethod = false;
    344   if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
    345     if (PDecl->meth_begin() == PDecl->meth_end())
    346       return HasAtleastOneRequiredProperty;
    347     for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
    348          MEnd = PDecl->meth_end(); M != MEnd; ++M) {
    349       ObjCMethodDecl *MD = (*M);
    350       if (MD->isImplicit())
    351         continue;
    352       if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
    353         continue;
    354       DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
    355       if (R.size() == 0)
    356         return false;
    357       bool match = false;
    358       HasAtleastOneRequiredMethod = true;
    359       for (unsigned I = 0, N = R.size(); I != N; ++I)
    360         if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
    361           if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
    362             match = true;
    363             break;
    364           }
    365       if (!match)
    366         return false;
    367     }
    368   }
    369   if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
    370     return true;
    371   return false;
    372 }
    373 
    374 static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
    375                     llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
    376                     const NSAPI &NS, edit::Commit &commit) {
    377   const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
    378   std::string ClassString;
    379   SourceLocation EndLoc =
    380   IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
    381 
    382   if (Protocols.empty()) {
    383     ClassString = '<';
    384     for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
    385       ClassString += ConformingProtocols[i]->getNameAsString();
    386       if (i != (e-1))
    387         ClassString += ", ";
    388     }
    389     ClassString += "> ";
    390   }
    391   else {
    392     ClassString = ", ";
    393     for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
    394       ClassString += ConformingProtocols[i]->getNameAsString();
    395       if (i != (e-1))
    396         ClassString += ", ";
    397     }
    398     ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
    399     EndLoc = *PL;
    400   }
    401 
    402   commit.insertAfterToken(EndLoc, ClassString);
    403   return true;
    404 }
    405 
    406 static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
    407                                 const TypedefDecl *TypedefDcl,
    408                                 const NSAPI &NS, edit::Commit &commit,
    409                                 bool IsNSIntegerType) {
    410   std::string ClassString =
    411     IsNSIntegerType ? "typedef NS_ENUM(NSInteger, " : "typedef NS_OPTIONS(NSUInteger, ";
    412   ClassString += TypedefDcl->getIdentifier()->getName();
    413   ClassString += ')';
    414   SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
    415   commit.replace(R, ClassString);
    416   SourceLocation EndOfTypedefLoc = TypedefDcl->getLocEnd();
    417   EndOfTypedefLoc = trans::findLocationAfterSemi(EndOfTypedefLoc, NS.getASTContext());
    418   if (!EndOfTypedefLoc.isInvalid()) {
    419     commit.remove(SourceRange(TypedefDcl->getLocStart(), EndOfTypedefLoc));
    420     return true;
    421   }
    422   return false;
    423 }
    424 
    425 static bool rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
    426                                 const TypedefDecl *TypedefDcl,
    427                                 const NSAPI &NS, edit::Commit &commit,
    428                                  bool IsNSIntegerType) {
    429   std::string ClassString =
    430     IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
    431   ClassString += TypedefDcl->getIdentifier()->getName();
    432   ClassString += ')';
    433   SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
    434   commit.replace(R, ClassString);
    435   SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
    436   commit.remove(SourceRange(TypedefLoc, TypedefLoc));
    437   return true;
    438 }
    439 
    440 static bool UseNSOptionsMacro(ASTContext &Ctx,
    441                               const EnumDecl *EnumDcl) {
    442   bool PowerOfTwo = true;
    443   for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
    444        EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
    445     EnumConstantDecl *Enumerator = (*EI);
    446     const Expr *InitExpr = Enumerator->getInitExpr();
    447     if (!InitExpr) {
    448       PowerOfTwo = false;
    449       continue;
    450     }
    451     InitExpr = InitExpr->IgnoreImpCasts();
    452     if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
    453       if (BO->isShiftOp() || BO->isBitwiseOp())
    454         return true;
    455 
    456     uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
    457     if (PowerOfTwo && EnumVal && !llvm::isPowerOf2_64(EnumVal))
    458       PowerOfTwo = false;
    459   }
    460   return PowerOfTwo;
    461 }
    462 
    463 void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
    464                                             const ObjCImplementationDecl *ImpDecl) {
    465   const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
    466   if (!IDecl || ObjCProtocolDecls.empty())
    467     return;
    468   // Find all implicit conforming protocols for this class
    469   // and make them explicit.
    470   llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
    471   Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
    472   llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
    473 
    474   for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
    475        ObjCProtocolDecls.begin(),
    476        E = ObjCProtocolDecls.end(); I != E; ++I)
    477     if (!ExplicitProtocols.count(*I))
    478       PotentialImplicitProtocols.push_back(*I);
    479 
    480   if (PotentialImplicitProtocols.empty())
    481     return;
    482 
    483   // go through list of non-optional methods and properties in each protocol
    484   // in the PotentialImplicitProtocols list. If class implements every one of the
    485   // methods and properties, then this class conforms to this protocol.
    486   llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
    487   for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
    488     if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
    489                                               PotentialImplicitProtocols[i]))
    490       ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
    491 
    492   if (ConformingProtocols.empty())
    493     return;
    494 
    495   // Further reduce number of conforming protocols. If protocol P1 is in the list
    496   // protocol P2 (P2<P1>), No need to include P1.
    497   llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
    498   for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
    499     bool DropIt = false;
    500     ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
    501     for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
    502       ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
    503       if (PDecl == TargetPDecl)
    504         continue;
    505       if (PDecl->lookupProtocolNamed(
    506             TargetPDecl->getDeclName().getAsIdentifierInfo())) {
    507         DropIt = true;
    508         break;
    509       }
    510     }
    511     if (!DropIt)
    512       MinimalConformingProtocols.push_back(TargetPDecl);
    513   }
    514   edit::Commit commit(*Editor);
    515   rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
    516                              *NSAPIObj, commit);
    517   Editor->commit(commit);
    518 }
    519 
    520 void ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
    521                                            const EnumDecl *EnumDcl,
    522                                            const TypedefDecl *TypedefDcl) {
    523   if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
    524       !TypedefDcl->getIdentifier())
    525     return;
    526 
    527   QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
    528   bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
    529   bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
    530 
    531   if (!IsNSIntegerType && !IsNSUIntegerType) {
    532     // Also check for typedef enum {...} TD;
    533     if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
    534       if (EnumTy->getDecl() == EnumDcl) {
    535         bool NSOptions = UseNSOptionsMacro(Ctx, EnumDcl);
    536         if (NSOptions) {
    537           if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
    538             return;
    539         }
    540         else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
    541           return;
    542         edit::Commit commit(*Editor);
    543         rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
    544         Editor->commit(commit);
    545       }
    546     }
    547     return;
    548   }
    549   if (IsNSIntegerType && UseNSOptionsMacro(Ctx, EnumDcl)) {
    550     // We may still use NS_OPTIONS based on what we find in the enumertor list.
    551     IsNSIntegerType = false;
    552     IsNSUIntegerType = true;
    553   }
    554 
    555   // NS_ENUM must be available.
    556   if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
    557     return;
    558   // NS_OPTIONS must be available.
    559   if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
    560     return;
    561   edit::Commit commit(*Editor);
    562   rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, IsNSIntegerType);
    563   Editor->commit(commit);
    564 }
    565 
    566 static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
    567                                     ObjCMethodDecl *OM) {
    568   SourceRange R;
    569   std::string ClassString;
    570   if (TypeSourceInfo *TSInfo =  OM->getResultTypeSourceInfo()) {
    571     TypeLoc TL = TSInfo->getTypeLoc();
    572     R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
    573     ClassString = "instancetype";
    574   }
    575   else {
    576     R = SourceRange(OM->getLocStart(), OM->getLocStart());
    577     ClassString = OM->isInstanceMethod() ? '-' : '+';
    578     ClassString += " (instancetype)";
    579   }
    580   edit::Commit commit(*ASTC.Editor);
    581   commit.replace(R, ClassString);
    582   ASTC.Editor->commit(commit);
    583 }
    584 
    585 void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
    586                                                        ObjCContainerDecl *CDecl,
    587                                                        ObjCMethodDecl *OM) {
    588   ObjCInstanceTypeFamily OIT_Family =
    589     Selector::getInstTypeMethodFamily(OM->getSelector());
    590 
    591   std::string ClassName;
    592   switch (OIT_Family) {
    593     case OIT_None:
    594       migrateFactoryMethod(Ctx, CDecl, OM);
    595       return;
    596     case OIT_Array:
    597       ClassName = "NSArray";
    598       break;
    599     case OIT_Dictionary:
    600       ClassName = "NSDictionary";
    601       break;
    602     case OIT_MemManage:
    603       ClassName = "NSObject";
    604       break;
    605     case OIT_Singleton:
    606       migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
    607       return;
    608   }
    609   if (!OM->getResultType()->isObjCIdType())
    610     return;
    611 
    612   ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
    613   if (!IDecl) {
    614     if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
    615       IDecl = CatDecl->getClassInterface();
    616     else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
    617       IDecl = ImpDecl->getClassInterface();
    618   }
    619   if (!IDecl ||
    620       !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
    621     migrateFactoryMethod(Ctx, CDecl, OM);
    622     return;
    623   }
    624   ReplaceWithInstancetype(*this, OM);
    625 }
    626 
    627 void ObjCMigrateASTConsumer::migrateInstanceType(ASTContext &Ctx,
    628                                                  ObjCContainerDecl *CDecl) {
    629   // migrate methods which can have instancetype as their result type.
    630   for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
    631        MEnd = CDecl->meth_end();
    632        M != MEnd; ++M) {
    633     ObjCMethodDecl *Method = (*M);
    634     migrateMethodInstanceType(Ctx, CDecl, Method);
    635   }
    636 }
    637 
    638 void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
    639                                                   ObjCContainerDecl *CDecl,
    640                                                   ObjCMethodDecl *OM,
    641                                                   ObjCInstanceTypeFamily OIT_Family) {
    642   if (OM->isInstanceMethod() ||
    643       OM->getResultType() == Ctx.getObjCInstanceType() ||
    644       !OM->getResultType()->isObjCIdType())
    645     return;
    646 
    647   // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
    648   // NSYYYNamE with matching names be at least 3 characters long.
    649   ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
    650   if (!IDecl) {
    651     if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
    652       IDecl = CatDecl->getClassInterface();
    653     else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
    654       IDecl = ImpDecl->getClassInterface();
    655   }
    656   if (!IDecl)
    657     return;
    658 
    659   std::string StringClassName = IDecl->getName();
    660   StringRef LoweredClassName(StringClassName);
    661   std::string StringLoweredClassName = LoweredClassName.lower();
    662   LoweredClassName = StringLoweredClassName;
    663 
    664   IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
    665   std::string MethodName = MethodIdName->getName();
    666   if (OIT_Family == OIT_Singleton) {
    667     StringRef STRefMethodName(MethodName);
    668     size_t len = 0;
    669     if (STRefMethodName.startswith("standard"))
    670       len = strlen("standard");
    671     else if (STRefMethodName.startswith("shared"))
    672       len = strlen("shared");
    673     else if (STRefMethodName.startswith("default"))
    674       len = strlen("default");
    675     else
    676       return;
    677     MethodName = STRefMethodName.substr(len);
    678   }
    679   std::string MethodNameSubStr = MethodName.substr(0, 3);
    680   StringRef MethodNamePrefix(MethodNameSubStr);
    681   std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
    682   MethodNamePrefix = StringLoweredMethodNamePrefix;
    683   size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
    684   if (Ix == StringRef::npos)
    685     return;
    686   std::string ClassNamePostfix = LoweredClassName.substr(Ix);
    687   StringRef LoweredMethodName(MethodName);
    688   std::string StringLoweredMethodName = LoweredMethodName.lower();
    689   LoweredMethodName = StringLoweredMethodName;
    690   if (!LoweredMethodName.startswith(ClassNamePostfix))
    691     return;
    692   ReplaceWithInstancetype(*this, OM);
    693 }
    694 
    695 namespace {
    696 
    697 class RewritesReceiver : public edit::EditsReceiver {
    698   Rewriter &Rewrite;
    699 
    700 public:
    701   RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
    702 
    703   virtual void insert(SourceLocation loc, StringRef text) {
    704     Rewrite.InsertText(loc, text);
    705   }
    706   virtual void replace(CharSourceRange range, StringRef text) {
    707     Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
    708   }
    709 };
    710 
    711 }
    712 
    713 void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
    714 
    715   TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
    716   if (MigrateProperty)
    717     for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
    718          D != DEnd; ++D) {
    719       if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
    720         migrateObjCInterfaceDecl(Ctx, CDecl);
    721       else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
    722         ObjCProtocolDecls.insert(PDecl);
    723       else if (const ObjCImplementationDecl *ImpDecl =
    724                dyn_cast<ObjCImplementationDecl>(*D))
    725         migrateProtocolConformance(Ctx, ImpDecl);
    726       else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
    727         DeclContext::decl_iterator N = D;
    728         ++N;
    729         if (N != DEnd)
    730           if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N))
    731             migrateNSEnumDecl(Ctx, ED, TD);
    732       }
    733       // migrate methods which can have instancetype as their result type.
    734       if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D))
    735         migrateInstanceType(Ctx, CDecl);
    736     }
    737 
    738   Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
    739   RewritesReceiver Rec(rewriter);
    740   Editor->applyRewrites(Rec);
    741 
    742   for (Rewriter::buffer_iterator
    743         I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
    744     FileID FID = I->first;
    745     RewriteBuffer &buf = I->second;
    746     const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
    747     assert(file);
    748     SmallString<512> newText;
    749     llvm::raw_svector_ostream vecOS(newText);
    750     buf.write(vecOS);
    751     vecOS.flush();
    752     llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
    753                    StringRef(newText.data(), newText.size()), file->getName());
    754     SmallString<64> filePath(file->getName());
    755     FileMgr.FixupRelativePath(filePath);
    756     Remapper.remap(filePath.str(), memBuf);
    757   }
    758 
    759   if (IsOutputFile) {
    760     Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
    761   } else {
    762     Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
    763   }
    764 }
    765 
    766 bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
    767   CI.getDiagnostics().setIgnoreAllWarnings(true);
    768   return true;
    769 }
    770 
    771 ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
    772                                                   StringRef InFile) {
    773   PPConditionalDirectiveRecord *
    774     PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
    775   CI.getPreprocessor().addPPCallbacks(PPRec);
    776   return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
    777                                     /*MigrateLiterals=*/true,
    778                                     /*MigrateSubscripting=*/true,
    779                                     /*MigrateProperty*/true,
    780                                     Remapper,
    781                                     CI.getFileManager(),
    782                                     PPRec,
    783                                     CI.getPreprocessor(),
    784                                     /*isOutputFile=*/true);
    785 }
    786