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