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