1234287Sdim//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
2234287Sdim//
3234287Sdim//                     The LLVM Compiler Infrastructure
4234287Sdim//
5234287Sdim// This file is distributed under the University of Illinois Open Source
6234287Sdim// License. See LICENSE.TXT for details.
7234287Sdim//
8234287Sdim//===----------------------------------------------------------------------===//
9234287Sdim
10263509Sdim#include "Transforms.h"
11234287Sdim#include "clang/ARCMigrate/ARCMTActions.h"
12252723Sdim#include "clang/AST/ASTConsumer.h"
13245431Sdim#include "clang/AST/ASTContext.h"
14252723Sdim#include "clang/AST/NSAPI.h"
15252723Sdim#include "clang/AST/ParentMap.h"
16234287Sdim#include "clang/AST/RecursiveASTVisitor.h"
17252723Sdim#include "clang/Basic/FileManager.h"
18252723Sdim#include "clang/Edit/Commit.h"
19234287Sdim#include "clang/Edit/EditedSource.h"
20234287Sdim#include "clang/Edit/EditsReceiver.h"
21252723Sdim#include "clang/Edit/Rewriters.h"
22252723Sdim#include "clang/Frontend/CompilerInstance.h"
23252723Sdim#include "clang/Frontend/MultiplexConsumer.h"
24252723Sdim#include "clang/Lex/PPConditionalDirectiveRecord.h"
25252723Sdim#include "clang/Lex/Preprocessor.h"
26245431Sdim#include "clang/Rewrite/Core/Rewriter.h"
27263509Sdim#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
28263509Sdim#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
29263509Sdim#include "clang/AST/Attr.h"
30234287Sdim#include "llvm/ADT/SmallString.h"
31263509Sdim#include "llvm/Support/Path.h"
32234287Sdim
33234287Sdimusing namespace clang;
34234287Sdimusing namespace arcmt;
35263509Sdimusing namespace ento::objc_retain;
36234287Sdim
37234287Sdimnamespace {
38234287Sdim
39234287Sdimclass ObjCMigrateASTConsumer : public ASTConsumer {
40263509Sdim  enum CF_BRIDGING_KIND {
41263509Sdim    CF_BRIDGING_NONE,
42263509Sdim    CF_BRIDGING_ENABLE,
43263509Sdim    CF_BRIDGING_MAY_INCLUDE
44263509Sdim  };
45263509Sdim
46234287Sdim  void migrateDecl(Decl *D);
47263509Sdim  void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D);
48263509Sdim  void migrateDeprecatedAnnotation(ASTContext &Ctx, ObjCCategoryDecl *CatDecl);
49263509Sdim  void migrateProtocolConformance(ASTContext &Ctx,
50263509Sdim                                  const ObjCImplementationDecl *ImpDecl);
51263509Sdim  void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
52263509Sdim  bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
53263509Sdim                     const TypedefDecl *TypedefDcl);
54263509Sdim  void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
55263509Sdim  void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
56263509Sdim                                 ObjCMethodDecl *OM);
57263509Sdim  bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
58263509Sdim  void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
59263509Sdim  void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
60263509Sdim  void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
61263509Sdim                            ObjCMethodDecl *OM,
62263509Sdim                            ObjCInstanceTypeFamily OIT_Family = OIT_None);
63263509Sdim
64263509Sdim  void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
65263509Sdim  void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
66263509Sdim                        const FunctionDecl *FuncDecl, bool ResultAnnotated);
67263509Sdim  void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
68263509Sdim                        const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
69263509Sdim
70263509Sdim  void AnnotateImplicitBridging(ASTContext &Ctx);
71263509Sdim
72263509Sdim  CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
73263509Sdim                                                const FunctionDecl *FuncDecl);
74263509Sdim
75263509Sdim  void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
76263509Sdim
77263509Sdim  void migrateAddMethodAnnotation(ASTContext &Ctx,
78263509Sdim                                  const ObjCMethodDecl *MethodDecl);
79234287Sdimpublic:
80234287Sdim  std::string MigrateDir;
81263509Sdim  unsigned ASTMigrateActions;
82263509Sdim  FileID FileId;
83263509Sdim  const TypedefDecl *NSIntegerTypedefed;
84263509Sdim  const TypedefDecl *NSUIntegerTypedefed;
85252723Sdim  OwningPtr<NSAPI> NSAPIObj;
86252723Sdim  OwningPtr<edit::EditedSource> Editor;
87234287Sdim  FileRemapper &Remapper;
88234287Sdim  FileManager &FileMgr;
89252723Sdim  const PPConditionalDirectiveRecord *PPRec;
90263509Sdim  Preprocessor &PP;
91234287Sdim  bool IsOutputFile;
92263509Sdim  llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
93263509Sdim  llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
94263509Sdim  llvm::StringMap<char> WhiteListFilenames;
95263509Sdim
96234287Sdim  ObjCMigrateASTConsumer(StringRef migrateDir,
97263509Sdim                         unsigned astMigrateActions,
98234287Sdim                         FileRemapper &remapper,
99234287Sdim                         FileManager &fileMgr,
100252723Sdim                         const PPConditionalDirectiveRecord *PPRec,
101263509Sdim                         Preprocessor &PP,
102263509Sdim                         bool isOutputFile,
103263509Sdim                         ArrayRef<std::string> WhiteList)
104234287Sdim  : MigrateDir(migrateDir),
105263509Sdim    ASTMigrateActions(astMigrateActions),
106263509Sdim    NSIntegerTypedefed(0), NSUIntegerTypedefed(0),
107263509Sdim    Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
108263509Sdim    IsOutputFile(isOutputFile) {
109234287Sdim
110263509Sdim    for (ArrayRef<std::string>::iterator
111263509Sdim           I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) {
112263509Sdim      WhiteListFilenames.GetOrCreateValue(*I);
113263509Sdim    }
114263509Sdim  }
115263509Sdim
116234287Sdimprotected:
117234287Sdim  virtual void Initialize(ASTContext &Context) {
118234287Sdim    NSAPIObj.reset(new NSAPI(Context));
119234287Sdim    Editor.reset(new edit::EditedSource(Context.getSourceManager(),
120234287Sdim                                        Context.getLangOpts(),
121263509Sdim                                        PPRec, false));
122234287Sdim  }
123234287Sdim
124234287Sdim  virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
125234287Sdim    for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
126234287Sdim      migrateDecl(*I);
127234287Sdim    return true;
128234287Sdim  }
129234287Sdim  virtual void HandleInterestingDecl(DeclGroupRef DG) {
130234287Sdim    // Ignore decls from the PCH.
131234287Sdim  }
132234287Sdim  virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
133234287Sdim    ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
134234287Sdim  }
135234287Sdim
136234287Sdim  virtual void HandleTranslationUnit(ASTContext &Ctx);
137263509Sdim
138263509Sdim  bool canModifyFile(StringRef Path) {
139263509Sdim    if (WhiteListFilenames.empty())
140263509Sdim      return true;
141263509Sdim    return WhiteListFilenames.find(llvm::sys::path::filename(Path))
142263509Sdim        != WhiteListFilenames.end();
143263509Sdim  }
144234287Sdim};
145234287Sdim
146234287Sdim}
147234287Sdim
148234287SdimObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
149263509Sdim                                     StringRef migrateDir,
150263509Sdim                                     unsigned migrateAction)
151234287Sdim  : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
152263509Sdim    ObjCMigAction(migrateAction),
153234287Sdim    CompInst(0) {
154234287Sdim  if (MigrateDir.empty())
155234287Sdim    MigrateDir = "."; // user current directory if none is given.
156234287Sdim}
157234287Sdim
158234287SdimASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
159234287Sdim                                                  StringRef InFile) {
160252723Sdim  PPConditionalDirectiveRecord *
161252723Sdim    PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
162252723Sdim  CompInst->getPreprocessor().addPPCallbacks(PPRec);
163234287Sdim  ASTConsumer *
164234287Sdim    WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
165234287Sdim  ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
166263509Sdim                                                       ObjCMigAction,
167234287Sdim                                                       Remapper,
168234287Sdim                                                    CompInst->getFileManager(),
169263509Sdim                                                       PPRec,
170263509Sdim                                                       CompInst->getPreprocessor(),
171263509Sdim                                                       false,
172263509Sdim                                                       ArrayRef<std::string>());
173234287Sdim  ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
174234287Sdim  return new MultiplexConsumer(Consumers);
175234287Sdim}
176234287Sdim
177234287Sdimbool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
178234287Sdim  Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
179234287Sdim                        /*ignoreIfFilesChanges=*/true);
180234287Sdim  CompInst = &CI;
181234287Sdim  CI.getDiagnostics().setIgnoreAllWarnings(true);
182234287Sdim  return true;
183234287Sdim}
184234287Sdim
185234287Sdimnamespace {
186234287Sdimclass ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
187234287Sdim  ObjCMigrateASTConsumer &Consumer;
188252723Sdim  ParentMap &PMap;
189234287Sdim
190234287Sdimpublic:
191252723Sdim  ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
192252723Sdim    : Consumer(consumer), PMap(PMap) { }
193234287Sdim
194234287Sdim  bool shouldVisitTemplateInstantiations() const { return false; }
195234287Sdim  bool shouldWalkTypesOfTypeLocs() const { return false; }
196234287Sdim
197234287Sdim  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
198263509Sdim    if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
199234287Sdim      edit::Commit commit(*Consumer.Editor);
200252723Sdim      edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
201234287Sdim      Consumer.Editor->commit(commit);
202234287Sdim    }
203234287Sdim
204263509Sdim    if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
205234287Sdim      edit::Commit commit(*Consumer.Editor);
206234287Sdim      edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
207234287Sdim      Consumer.Editor->commit(commit);
208234287Sdim    }
209234287Sdim
210234287Sdim    return true;
211234287Sdim  }
212234287Sdim
213234287Sdim  bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
214234287Sdim    // Do depth first; we want to rewrite the subexpressions first so that if
215234287Sdim    // we have to move expressions we will move them already rewritten.
216234287Sdim    for (Stmt::child_range range = E->children(); range; ++range)
217234287Sdim      if (!TraverseStmt(*range))
218234287Sdim        return false;
219234287Sdim
220234287Sdim    return WalkUpFromObjCMessageExpr(E);
221234287Sdim  }
222234287Sdim};
223252723Sdim
224252723Sdimclass BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
225252723Sdim  ObjCMigrateASTConsumer &Consumer;
226252723Sdim  OwningPtr<ParentMap> PMap;
227252723Sdim
228252723Sdimpublic:
229252723Sdim  BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
230252723Sdim
231252723Sdim  bool shouldVisitTemplateInstantiations() const { return false; }
232252723Sdim  bool shouldWalkTypesOfTypeLocs() const { return false; }
233252723Sdim
234252723Sdim  bool TraverseStmt(Stmt *S) {
235252723Sdim    PMap.reset(new ParentMap(S));
236252723Sdim    ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
237252723Sdim    return true;
238252723Sdim  }
239252723Sdim};
240234287Sdim}
241234287Sdim
242234287Sdimvoid ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
243234287Sdim  if (!D)
244234287Sdim    return;
245234287Sdim  if (isa<ObjCMethodDecl>(D))
246234287Sdim    return; // Wait for the ObjC container declaration.
247234287Sdim
248252723Sdim  BodyMigrator(*this).TraverseDecl(D);
249234287Sdim}
250234287Sdim
251263509Sdimstatic void append_attr(std::string &PropertyString, const char *attr,
252263509Sdim                        bool &LParenAdded) {
253263509Sdim  if (!LParenAdded) {
254263509Sdim    PropertyString += "(";
255263509Sdim    LParenAdded = true;
256263509Sdim  }
257263509Sdim  else
258263509Sdim    PropertyString += ", ";
259263509Sdim  PropertyString += attr;
260263509Sdim}
261263509Sdim
262263509Sdimstatic
263263509Sdimvoid MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
264263509Sdim                                               const std::string& TypeString,
265263509Sdim                                               const char *name) {
266263509Sdim  const char *argPtr = TypeString.c_str();
267263509Sdim  int paren = 0;
268263509Sdim  while (*argPtr) {
269263509Sdim    switch (*argPtr) {
270263509Sdim      case '(':
271263509Sdim        PropertyString += *argPtr;
272263509Sdim        paren++;
273263509Sdim        break;
274263509Sdim      case ')':
275263509Sdim        PropertyString += *argPtr;
276263509Sdim        paren--;
277263509Sdim        break;
278263509Sdim      case '^':
279263509Sdim      case '*':
280263509Sdim        PropertyString += (*argPtr);
281263509Sdim        if (paren == 1) {
282263509Sdim          PropertyString += name;
283263509Sdim          name = "";
284263509Sdim        }
285263509Sdim        break;
286263509Sdim      default:
287263509Sdim        PropertyString += *argPtr;
288263509Sdim        break;
289263509Sdim    }
290263509Sdim    argPtr++;
291263509Sdim  }
292263509Sdim}
293263509Sdim
294263509Sdimstatic const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
295263509Sdim  Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
296263509Sdim  bool RetainableObject = ArgType->isObjCRetainableType();
297263509Sdim  if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
298263509Sdim    if (const ObjCObjectPointerType *ObjPtrTy =
299263509Sdim        ArgType->getAs<ObjCObjectPointerType>()) {
300263509Sdim      ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
301263509Sdim      if (IDecl &&
302263509Sdim          IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
303263509Sdim        return "copy";
304263509Sdim      else
305263509Sdim        return "retain";
306263509Sdim    }
307263509Sdim    else if (ArgType->isBlockPointerType())
308263509Sdim      return "copy";
309263509Sdim  } else if (propertyLifetime == Qualifiers::OCL_Weak)
310263509Sdim    // TODO. More precise determination of 'weak' attribute requires
311263509Sdim    // looking into setter's implementation for backing weak ivar.
312263509Sdim    return "weak";
313263509Sdim  else if (RetainableObject)
314263509Sdim    return ArgType->isBlockPointerType() ? "copy" : "retain";
315263509Sdim  return 0;
316263509Sdim}
317263509Sdim
318263509Sdimstatic void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
319263509Sdim                                  const ObjCMethodDecl *Setter,
320263509Sdim                                  const NSAPI &NS, edit::Commit &commit,
321263509Sdim                                  unsigned LengthOfPrefix,
322263509Sdim                                  bool Atomic, bool UseNsIosOnlyMacro,
323263509Sdim                                  bool AvailabilityArgsMatch) {
324263509Sdim  ASTContext &Context = NS.getASTContext();
325263509Sdim  bool LParenAdded = false;
326263509Sdim  std::string PropertyString = "@property ";
327263509Sdim  if (UseNsIosOnlyMacro && Context.Idents.get("NS_NONATOMIC_IOSONLY").hasMacroDefinition()) {
328263509Sdim    PropertyString += "(NS_NONATOMIC_IOSONLY";
329263509Sdim    LParenAdded = true;
330263509Sdim  } else if (!Atomic) {
331263509Sdim    PropertyString += "(nonatomic";
332263509Sdim    LParenAdded = true;
333263509Sdim  }
334263509Sdim
335263509Sdim  std::string PropertyNameString = Getter->getNameAsString();
336263509Sdim  StringRef PropertyName(PropertyNameString);
337263509Sdim  if (LengthOfPrefix > 0) {
338263509Sdim    if (!LParenAdded) {
339263509Sdim      PropertyString += "(getter=";
340263509Sdim      LParenAdded = true;
341263509Sdim    }
342263509Sdim    else
343263509Sdim      PropertyString += ", getter=";
344263509Sdim    PropertyString += PropertyNameString;
345263509Sdim  }
346263509Sdim  // Property with no setter may be suggested as a 'readonly' property.
347263509Sdim  if (!Setter) {
348263509Sdim    append_attr(PropertyString, "readonly", LParenAdded);
349263509Sdim    QualType ResType = Context.getCanonicalType(Getter->getResultType());
350263509Sdim    if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
351263509Sdim      append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
352263509Sdim  }
353263509Sdim
354263509Sdim  // Short circuit 'delegate' properties that contain the name "delegate" or
355263509Sdim  // "dataSource", or have exact name "target" to have 'assign' attribute.
356263509Sdim  if (PropertyName.equals("target") ||
357263509Sdim      (PropertyName.find("delegate") != StringRef::npos) ||
358263509Sdim      (PropertyName.find("dataSource") != StringRef::npos)) {
359263509Sdim    QualType QT = Getter->getResultType();
360263509Sdim    if (!QT->isRealType())
361263509Sdim      append_attr(PropertyString, "assign", LParenAdded);
362263509Sdim  }
363263509Sdim  else if (Setter) {
364263509Sdim    const ParmVarDecl *argDecl = *Setter->param_begin();
365263509Sdim    QualType ArgType = Context.getCanonicalType(argDecl->getType());
366263509Sdim    if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
367263509Sdim      append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
368263509Sdim  }
369263509Sdim  if (LParenAdded)
370263509Sdim    PropertyString += ')';
371263509Sdim  QualType RT = Getter->getResultType();
372263509Sdim  if (!isa<TypedefType>(RT)) {
373263509Sdim    // strip off any ARC lifetime qualifier.
374263509Sdim    QualType CanResultTy = Context.getCanonicalType(RT);
375263509Sdim    if (CanResultTy.getQualifiers().hasObjCLifetime()) {
376263509Sdim      Qualifiers Qs = CanResultTy.getQualifiers();
377263509Sdim      Qs.removeObjCLifetime();
378263509Sdim      RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
379263509Sdim    }
380263509Sdim  }
381263509Sdim  PropertyString += " ";
382263509Sdim  PrintingPolicy SubPolicy(Context.getPrintingPolicy());
383263509Sdim  SubPolicy.SuppressStrongLifetime = true;
384263509Sdim  SubPolicy.SuppressLifetimeQualifiers = true;
385263509Sdim  std::string TypeString = RT.getAsString(SubPolicy);
386263509Sdim  if (LengthOfPrefix > 0) {
387263509Sdim    // property name must strip off "is" and lower case the first character
388263509Sdim    // after that; e.g. isContinuous will become continuous.
389263509Sdim    StringRef PropertyNameStringRef(PropertyNameString);
390263509Sdim    PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
391263509Sdim    PropertyNameString = PropertyNameStringRef;
392263509Sdim    bool NoLowering = (isUppercase(PropertyNameString[0]) &&
393263509Sdim                       PropertyNameString.size() > 1 &&
394263509Sdim                       isUppercase(PropertyNameString[1]));
395263509Sdim    if (!NoLowering)
396263509Sdim      PropertyNameString[0] = toLowercase(PropertyNameString[0]);
397263509Sdim  }
398263509Sdim  if (RT->isBlockPointerType() || RT->isFunctionPointerType())
399263509Sdim    MigrateBlockOrFunctionPointerTypeVariable(PropertyString,
400263509Sdim                                              TypeString,
401263509Sdim                                              PropertyNameString.c_str());
402263509Sdim  else {
403263509Sdim    char LastChar = TypeString[TypeString.size()-1];
404263509Sdim    PropertyString += TypeString;
405263509Sdim    if (LastChar != '*')
406263509Sdim      PropertyString += ' ';
407263509Sdim    PropertyString += PropertyNameString;
408263509Sdim  }
409263509Sdim  SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
410263509Sdim  Selector GetterSelector = Getter->getSelector();
411263509Sdim
412263509Sdim  SourceLocation EndGetterSelectorLoc =
413263509Sdim    StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
414263509Sdim  commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
415263509Sdim                                               EndGetterSelectorLoc),
416263509Sdim                 PropertyString);
417263509Sdim  if (Setter && AvailabilityArgsMatch) {
418263509Sdim    SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
419263509Sdim    // Get location past ';'
420263509Sdim    EndLoc = EndLoc.getLocWithOffset(1);
421263509Sdim    SourceLocation BeginOfSetterDclLoc = Setter->getLocStart();
422263509Sdim    // FIXME. This assumes that setter decl; is immediately preceeded by eoln.
423263509Sdim    // It is trying to remove the setter method decl. line entirely.
424263509Sdim    BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
425263509Sdim    commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
426263509Sdim  }
427263509Sdim}
428263509Sdim
429263509Sdimvoid ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
430263509Sdim                                                      ObjCContainerDecl *D) {
431263509Sdim  if (D->isDeprecated())
432263509Sdim    return;
433263509Sdim
434263509Sdim  for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
435263509Sdim       M != MEnd; ++M) {
436263509Sdim    ObjCMethodDecl *Method = (*M);
437263509Sdim    if (Method->isDeprecated())
438263509Sdim      continue;
439263509Sdim    bool PropertyInferred = migrateProperty(Ctx, D, Method);
440263509Sdim    // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to
441263509Sdim    // the getter method as it ends up on the property itself which we don't want
442263509Sdim    // to do unless -objcmt-returns-innerpointer-property  option is on.
443263509Sdim    if (!PropertyInferred ||
444263509Sdim        (ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
445263509Sdim      if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
446263509Sdim        migrateNsReturnsInnerPointer(Ctx, Method);
447263509Sdim  }
448263509Sdim  if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
449263509Sdim    return;
450263509Sdim
451263509Sdim  for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
452263509Sdim       E = D->prop_end(); P != E; ++P) {
453263509Sdim    ObjCPropertyDecl *Prop = *P;
454263509Sdim    if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
455263509Sdim        !Prop->isDeprecated())
456263509Sdim      migratePropertyNsReturnsInnerPointer(Ctx, Prop);
457263509Sdim  }
458263509Sdim}
459263509Sdim
460263509Sdimvoid ObjCMigrateASTConsumer::migrateDeprecatedAnnotation(ASTContext &Ctx,
461263509Sdim                                                           ObjCCategoryDecl *CatDecl) {
462263509Sdim  StringRef Name = CatDecl->getName();
463263509Sdim  if (!Name.endswith("Deprecated"))
464263509Sdim    return;
465263509Sdim
466263509Sdim  if (!Ctx.Idents.get("DEPRECATED").hasMacroDefinition())
467263509Sdim    return;
468263509Sdim
469263509Sdim  ObjCContainerDecl *D = cast<ObjCContainerDecl>(CatDecl);
470263509Sdim
471263509Sdim  for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
472263509Sdim       M != MEnd; ++M) {
473263509Sdim    ObjCMethodDecl *Method = (*M);
474263509Sdim    if (Method->isDeprecated() || Method->isImplicit())
475263509Sdim      continue;
476263509Sdim    // Annotate with DEPRECATED
477263509Sdim    edit::Commit commit(*Editor);
478263509Sdim    commit.insertBefore(Method->getLocEnd(), " DEPRECATED");
479263509Sdim    Editor->commit(commit);
480263509Sdim  }
481263509Sdim  for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
482263509Sdim       E = D->prop_end(); P != E; ++P) {
483263509Sdim    ObjCPropertyDecl *Prop = *P;
484263509Sdim    if (Prop->isDeprecated())
485263509Sdim      continue;
486263509Sdim    // Annotate with DEPRECATED
487263509Sdim    edit::Commit commit(*Editor);
488263509Sdim    commit.insertAfterToken(Prop->getLocEnd(), " DEPRECATED");
489263509Sdim    Editor->commit(commit);
490263509Sdim  }
491263509Sdim}
492263509Sdim
493263509Sdimstatic bool
494263509SdimClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
495263509Sdim                                      const ObjCImplementationDecl *ImpDecl,
496263509Sdim                                       const ObjCInterfaceDecl *IDecl,
497263509Sdim                                      ObjCProtocolDecl *Protocol) {
498263509Sdim  // In auto-synthesis, protocol properties are not synthesized. So,
499263509Sdim  // a conforming protocol must have its required properties declared
500263509Sdim  // in class interface.
501263509Sdim  bool HasAtleastOneRequiredProperty = false;
502263509Sdim  if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
503263509Sdim    for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
504263509Sdim         E = PDecl->prop_end(); P != E; ++P) {
505263509Sdim      ObjCPropertyDecl *Property = *P;
506263509Sdim      if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
507263509Sdim        continue;
508263509Sdim      HasAtleastOneRequiredProperty = true;
509263509Sdim      DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
510263509Sdim      if (R.size() == 0) {
511263509Sdim        // Relax the rule and look into class's implementation for a synthesize
512263509Sdim        // or dynamic declaration. Class is implementing a property coming from
513263509Sdim        // another protocol. This still makes the target protocol as conforming.
514263509Sdim        if (!ImpDecl->FindPropertyImplDecl(
515263509Sdim                                  Property->getDeclName().getAsIdentifierInfo()))
516263509Sdim          return false;
517263509Sdim      }
518263509Sdim      else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
519263509Sdim          if ((ClassProperty->getPropertyAttributes()
520263509Sdim              != Property->getPropertyAttributes()) ||
521263509Sdim              !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
522263509Sdim            return false;
523263509Sdim      }
524263509Sdim      else
525263509Sdim        return false;
526263509Sdim    }
527263509Sdim
528263509Sdim  // At this point, all required properties in this protocol conform to those
529263509Sdim  // declared in the class.
530263509Sdim  // Check that class implements the required methods of the protocol too.
531263509Sdim  bool HasAtleastOneRequiredMethod = false;
532263509Sdim  if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
533263509Sdim    if (PDecl->meth_begin() == PDecl->meth_end())
534263509Sdim      return HasAtleastOneRequiredProperty;
535263509Sdim    for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
536263509Sdim         MEnd = PDecl->meth_end(); M != MEnd; ++M) {
537263509Sdim      ObjCMethodDecl *MD = (*M);
538263509Sdim      if (MD->isImplicit())
539263509Sdim        continue;
540263509Sdim      if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
541263509Sdim        continue;
542263509Sdim      DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
543263509Sdim      if (R.size() == 0)
544263509Sdim        return false;
545263509Sdim      bool match = false;
546263509Sdim      HasAtleastOneRequiredMethod = true;
547263509Sdim      for (unsigned I = 0, N = R.size(); I != N; ++I)
548263509Sdim        if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
549263509Sdim          if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
550263509Sdim            match = true;
551263509Sdim            break;
552263509Sdim          }
553263509Sdim      if (!match)
554263509Sdim        return false;
555263509Sdim    }
556263509Sdim  }
557263509Sdim  if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
558263509Sdim    return true;
559263509Sdim  return false;
560263509Sdim}
561263509Sdim
562263509Sdimstatic bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
563263509Sdim                    llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
564263509Sdim                    const NSAPI &NS, edit::Commit &commit) {
565263509Sdim  const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
566263509Sdim  std::string ClassString;
567263509Sdim  SourceLocation EndLoc =
568263509Sdim  IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
569263509Sdim
570263509Sdim  if (Protocols.empty()) {
571263509Sdim    ClassString = '<';
572263509Sdim    for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
573263509Sdim      ClassString += ConformingProtocols[i]->getNameAsString();
574263509Sdim      if (i != (e-1))
575263509Sdim        ClassString += ", ";
576263509Sdim    }
577263509Sdim    ClassString += "> ";
578263509Sdim  }
579263509Sdim  else {
580263509Sdim    ClassString = ", ";
581263509Sdim    for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
582263509Sdim      ClassString += ConformingProtocols[i]->getNameAsString();
583263509Sdim      if (i != (e-1))
584263509Sdim        ClassString += ", ";
585263509Sdim    }
586263509Sdim    ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
587263509Sdim    EndLoc = *PL;
588263509Sdim  }
589263509Sdim
590263509Sdim  commit.insertAfterToken(EndLoc, ClassString);
591263509Sdim  return true;
592263509Sdim}
593263509Sdim
594263509Sdimstatic bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
595263509Sdim                                const TypedefDecl *TypedefDcl,
596263509Sdim                                const NSAPI &NS, edit::Commit &commit,
597263509Sdim                                bool IsNSIntegerType,
598263509Sdim                                bool NSOptions) {
599263509Sdim  std::string ClassString;
600263509Sdim  if (NSOptions)
601263509Sdim    ClassString = "typedef NS_OPTIONS(NSUInteger, ";
602263509Sdim  else
603263509Sdim    ClassString =
604263509Sdim      IsNSIntegerType ? "typedef NS_ENUM(NSInteger, "
605263509Sdim                      : "typedef NS_ENUM(NSUInteger, ";
606263509Sdim
607263509Sdim  ClassString += TypedefDcl->getIdentifier()->getName();
608263509Sdim  ClassString += ')';
609263509Sdim  SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
610263509Sdim  commit.replace(R, ClassString);
611263509Sdim  SourceLocation EndOfEnumDclLoc = EnumDcl->getLocEnd();
612263509Sdim  EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
613263509Sdim                                                 NS.getASTContext(), /*IsDecl*/true);
614263509Sdim  if (!EndOfEnumDclLoc.isInvalid()) {
615263509Sdim    SourceRange EnumDclRange(EnumDcl->getLocStart(), EndOfEnumDclLoc);
616263509Sdim    commit.insertFromRange(TypedefDcl->getLocStart(), EnumDclRange);
617263509Sdim  }
618263509Sdim  else
619263509Sdim    return false;
620263509Sdim
621263509Sdim  SourceLocation EndTypedefDclLoc = TypedefDcl->getLocEnd();
622263509Sdim  EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
623263509Sdim                                                 NS.getASTContext(), /*IsDecl*/true);
624263509Sdim  if (!EndTypedefDclLoc.isInvalid()) {
625263509Sdim    SourceRange TDRange(TypedefDcl->getLocStart(), EndTypedefDclLoc);
626263509Sdim    commit.remove(TDRange);
627263509Sdim  }
628263509Sdim  else
629263509Sdim    return false;
630263509Sdim
631263509Sdim  EndOfEnumDclLoc = trans::findLocationAfterSemi(EnumDcl->getLocEnd(), NS.getASTContext(),
632263509Sdim                                                 /*IsDecl*/true);
633263509Sdim  if (!EndOfEnumDclLoc.isInvalid()) {
634263509Sdim    SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart();
635263509Sdim    // FIXME. This assumes that enum decl; is immediately preceeded by eoln.
636263509Sdim    // It is trying to remove the enum decl. lines entirely.
637263509Sdim    BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
638263509Sdim    commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
639263509Sdim    return true;
640263509Sdim  }
641263509Sdim  return false;
642263509Sdim}
643263509Sdim
644263509Sdimstatic void rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
645263509Sdim                                const TypedefDecl *TypedefDcl,
646263509Sdim                                const NSAPI &NS, edit::Commit &commit,
647263509Sdim                                 bool IsNSIntegerType) {
648263509Sdim  std::string ClassString =
649263509Sdim    IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
650263509Sdim  ClassString += TypedefDcl->getIdentifier()->getName();
651263509Sdim  ClassString += ')';
652263509Sdim  SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
653263509Sdim  commit.replace(R, ClassString);
654263509Sdim  SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
655263509Sdim  commit.remove(SourceRange(TypedefLoc, TypedefLoc));
656263509Sdim}
657263509Sdim
658263509Sdimstatic bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
659263509Sdim                              const EnumDecl *EnumDcl) {
660263509Sdim  bool PowerOfTwo = true;
661263509Sdim  bool AllHexdecimalEnumerator = true;
662263509Sdim  uint64_t MaxPowerOfTwoVal = 0;
663263509Sdim  for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
664263509Sdim       EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
665263509Sdim    EnumConstantDecl *Enumerator = (*EI);
666263509Sdim    const Expr *InitExpr = Enumerator->getInitExpr();
667263509Sdim    if (!InitExpr) {
668263509Sdim      PowerOfTwo = false;
669263509Sdim      AllHexdecimalEnumerator = false;
670263509Sdim      continue;
671263509Sdim    }
672263509Sdim    InitExpr = InitExpr->IgnoreParenCasts();
673263509Sdim    if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
674263509Sdim      if (BO->isShiftOp() || BO->isBitwiseOp())
675263509Sdim        return true;
676263509Sdim
677263509Sdim    uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
678263509Sdim    if (PowerOfTwo && EnumVal) {
679263509Sdim      if (!llvm::isPowerOf2_64(EnumVal))
680263509Sdim        PowerOfTwo = false;
681263509Sdim      else if (EnumVal > MaxPowerOfTwoVal)
682263509Sdim        MaxPowerOfTwoVal = EnumVal;
683263509Sdim    }
684263509Sdim    if (AllHexdecimalEnumerator && EnumVal) {
685263509Sdim      bool FoundHexdecimalEnumerator = false;
686263509Sdim      SourceLocation EndLoc = Enumerator->getLocEnd();
687263509Sdim      Token Tok;
688263509Sdim      if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
689263509Sdim        if (Tok.isLiteral() && Tok.getLength() > 2) {
690263509Sdim          if (const char *StringLit = Tok.getLiteralData())
691263509Sdim            FoundHexdecimalEnumerator =
692263509Sdim              (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
693263509Sdim        }
694263509Sdim      if (!FoundHexdecimalEnumerator)
695263509Sdim        AllHexdecimalEnumerator = false;
696263509Sdim    }
697263509Sdim  }
698263509Sdim  return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
699263509Sdim}
700263509Sdim
701263509Sdimvoid ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
702263509Sdim                                            const ObjCImplementationDecl *ImpDecl) {
703263509Sdim  const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
704263509Sdim  if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
705263509Sdim    return;
706263509Sdim  // Find all implicit conforming protocols for this class
707263509Sdim  // and make them explicit.
708263509Sdim  llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
709263509Sdim  Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
710263509Sdim  llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
711263509Sdim
712263509Sdim  for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
713263509Sdim       ObjCProtocolDecls.begin(),
714263509Sdim       E = ObjCProtocolDecls.end(); I != E; ++I)
715263509Sdim    if (!ExplicitProtocols.count(*I))
716263509Sdim      PotentialImplicitProtocols.push_back(*I);
717263509Sdim
718263509Sdim  if (PotentialImplicitProtocols.empty())
719263509Sdim    return;
720263509Sdim
721263509Sdim  // go through list of non-optional methods and properties in each protocol
722263509Sdim  // in the PotentialImplicitProtocols list. If class implements every one of the
723263509Sdim  // methods and properties, then this class conforms to this protocol.
724263509Sdim  llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
725263509Sdim  for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
726263509Sdim    if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
727263509Sdim                                              PotentialImplicitProtocols[i]))
728263509Sdim      ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
729263509Sdim
730263509Sdim  if (ConformingProtocols.empty())
731263509Sdim    return;
732263509Sdim
733263509Sdim  // Further reduce number of conforming protocols. If protocol P1 is in the list
734263509Sdim  // protocol P2 (P2<P1>), No need to include P1.
735263509Sdim  llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
736263509Sdim  for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
737263509Sdim    bool DropIt = false;
738263509Sdim    ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
739263509Sdim    for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
740263509Sdim      ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
741263509Sdim      if (PDecl == TargetPDecl)
742263509Sdim        continue;
743263509Sdim      if (PDecl->lookupProtocolNamed(
744263509Sdim            TargetPDecl->getDeclName().getAsIdentifierInfo())) {
745263509Sdim        DropIt = true;
746263509Sdim        break;
747263509Sdim      }
748263509Sdim    }
749263509Sdim    if (!DropIt)
750263509Sdim      MinimalConformingProtocols.push_back(TargetPDecl);
751263509Sdim  }
752263509Sdim  edit::Commit commit(*Editor);
753263509Sdim  rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
754263509Sdim                             *NSAPIObj, commit);
755263509Sdim  Editor->commit(commit);
756263509Sdim}
757263509Sdim
758263509Sdimvoid ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
759263509Sdim                                          const TypedefDecl *TypedefDcl) {
760263509Sdim
761263509Sdim  QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
762263509Sdim  if (NSAPIObj->isObjCNSIntegerType(qt))
763263509Sdim    NSIntegerTypedefed = TypedefDcl;
764263509Sdim  else if (NSAPIObj->isObjCNSUIntegerType(qt))
765263509Sdim    NSUIntegerTypedefed = TypedefDcl;
766263509Sdim}
767263509Sdim
768263509Sdimbool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
769263509Sdim                                           const EnumDecl *EnumDcl,
770263509Sdim                                           const TypedefDecl *TypedefDcl) {
771263509Sdim  if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
772263509Sdim      EnumDcl->isDeprecated())
773263509Sdim    return false;
774263509Sdim  if (!TypedefDcl) {
775263509Sdim    if (NSIntegerTypedefed) {
776263509Sdim      TypedefDcl = NSIntegerTypedefed;
777263509Sdim      NSIntegerTypedefed = 0;
778263509Sdim    }
779263509Sdim    else if (NSUIntegerTypedefed) {
780263509Sdim      TypedefDcl = NSUIntegerTypedefed;
781263509Sdim      NSUIntegerTypedefed = 0;
782263509Sdim    }
783263509Sdim    else
784263509Sdim      return false;
785263509Sdim    FileID FileIdOfTypedefDcl =
786263509Sdim      PP.getSourceManager().getFileID(TypedefDcl->getLocation());
787263509Sdim    FileID FileIdOfEnumDcl =
788263509Sdim      PP.getSourceManager().getFileID(EnumDcl->getLocation());
789263509Sdim    if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
790263509Sdim      return false;
791263509Sdim  }
792263509Sdim  if (TypedefDcl->isDeprecated())
793263509Sdim    return false;
794263509Sdim
795263509Sdim  QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
796263509Sdim  bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
797263509Sdim  bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
798263509Sdim
799263509Sdim  if (!IsNSIntegerType && !IsNSUIntegerType) {
800263509Sdim    // Also check for typedef enum {...} TD;
801263509Sdim    if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
802263509Sdim      if (EnumTy->getDecl() == EnumDcl) {
803263509Sdim        bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
804263509Sdim        if (NSOptions) {
805263509Sdim          if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
806263509Sdim            return false;
807263509Sdim        }
808263509Sdim        else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
809263509Sdim          return false;
810263509Sdim        edit::Commit commit(*Editor);
811263509Sdim        rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
812263509Sdim        Editor->commit(commit);
813263509Sdim        return true;
814263509Sdim      }
815263509Sdim    }
816263509Sdim    return false;
817263509Sdim  }
818263509Sdim
819263509Sdim  // We may still use NS_OPTIONS based on what we find in the enumertor list.
820263509Sdim  bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
821263509Sdim  // NS_ENUM must be available.
822263509Sdim  if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
823263509Sdim    return false;
824263509Sdim  // NS_OPTIONS must be available.
825263509Sdim  if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
826263509Sdim    return false;
827263509Sdim  edit::Commit commit(*Editor);
828263509Sdim  bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
829263509Sdim                                 commit, IsNSIntegerType, NSOptions);
830263509Sdim  Editor->commit(commit);
831263509Sdim  return Res;
832263509Sdim}
833263509Sdim
834263509Sdimstatic void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
835263509Sdim                                    ObjCMethodDecl *OM) {
836263509Sdim  SourceRange R;
837263509Sdim  std::string ClassString;
838263509Sdim  if (TypeSourceInfo *TSInfo =  OM->getResultTypeSourceInfo()) {
839263509Sdim    TypeLoc TL = TSInfo->getTypeLoc();
840263509Sdim    R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
841263509Sdim    ClassString = "instancetype";
842263509Sdim  }
843263509Sdim  else {
844263509Sdim    R = SourceRange(OM->getLocStart(), OM->getLocStart());
845263509Sdim    ClassString = OM->isInstanceMethod() ? '-' : '+';
846263509Sdim    ClassString += " (instancetype)";
847263509Sdim  }
848263509Sdim  edit::Commit commit(*ASTC.Editor);
849263509Sdim  commit.replace(R, ClassString);
850263509Sdim  ASTC.Editor->commit(commit);
851263509Sdim}
852263509Sdim
853263509Sdimstatic void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
854263509Sdim                                    ObjCMethodDecl *OM) {
855263509Sdim  ObjCInterfaceDecl *IDecl = OM->getClassInterface();
856263509Sdim  SourceRange R;
857263509Sdim  std::string ClassString;
858263509Sdim  if (TypeSourceInfo *TSInfo =  OM->getResultTypeSourceInfo()) {
859263509Sdim    TypeLoc TL = TSInfo->getTypeLoc();
860263509Sdim    R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
861263509Sdim      ClassString  = IDecl->getName();
862263509Sdim      ClassString += "*";
863263509Sdim    }
864263509Sdim  }
865263509Sdim  else {
866263509Sdim    R = SourceRange(OM->getLocStart(), OM->getLocStart());
867263509Sdim    ClassString = "+ (";
868263509Sdim    ClassString += IDecl->getName(); ClassString += "*)";
869263509Sdim  }
870263509Sdim  edit::Commit commit(*ASTC.Editor);
871263509Sdim  commit.replace(R, ClassString);
872263509Sdim  ASTC.Editor->commit(commit);
873263509Sdim}
874263509Sdim
875263509Sdimvoid ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
876263509Sdim                                                       ObjCContainerDecl *CDecl,
877263509Sdim                                                       ObjCMethodDecl *OM) {
878263509Sdim  ObjCInstanceTypeFamily OIT_Family =
879263509Sdim    Selector::getInstTypeMethodFamily(OM->getSelector());
880263509Sdim
881263509Sdim  std::string ClassName;
882263509Sdim  switch (OIT_Family) {
883263509Sdim    case OIT_None:
884263509Sdim      migrateFactoryMethod(Ctx, CDecl, OM);
885263509Sdim      return;
886263509Sdim    case OIT_Array:
887263509Sdim      ClassName = "NSArray";
888263509Sdim      break;
889263509Sdim    case OIT_Dictionary:
890263509Sdim      ClassName = "NSDictionary";
891263509Sdim      break;
892263509Sdim    case OIT_Singleton:
893263509Sdim      migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
894263509Sdim      return;
895263509Sdim    case OIT_Init:
896263509Sdim      if (OM->getResultType()->isObjCIdType())
897263509Sdim        ReplaceWithInstancetype(*this, OM);
898263509Sdim      return;
899263509Sdim    case OIT_ReturnsSelf:
900263509Sdim      migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
901263509Sdim      return;
902263509Sdim  }
903263509Sdim  if (!OM->getResultType()->isObjCIdType())
904263509Sdim    return;
905263509Sdim
906263509Sdim  ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
907263509Sdim  if (!IDecl) {
908263509Sdim    if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
909263509Sdim      IDecl = CatDecl->getClassInterface();
910263509Sdim    else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
911263509Sdim      IDecl = ImpDecl->getClassInterface();
912263509Sdim  }
913263509Sdim  if (!IDecl ||
914263509Sdim      !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
915263509Sdim    migrateFactoryMethod(Ctx, CDecl, OM);
916263509Sdim    return;
917263509Sdim  }
918263509Sdim  ReplaceWithInstancetype(*this, OM);
919263509Sdim}
920263509Sdim
921263509Sdimstatic bool TypeIsInnerPointer(QualType T) {
922263509Sdim  if (!T->isAnyPointerType())
923263509Sdim    return false;
924263509Sdim  if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
925263509Sdim      T->isBlockPointerType() || T->isFunctionPointerType() ||
926263509Sdim      ento::coreFoundation::isCFObjectRef(T))
927263509Sdim    return false;
928263509Sdim  // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
929263509Sdim  // is not an innter pointer type.
930263509Sdim  QualType OrigT = T;
931263509Sdim  while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr()))
932263509Sdim    T = TD->getDecl()->getUnderlyingType();
933263509Sdim  if (OrigT == T || !T->isPointerType())
934263509Sdim    return true;
935263509Sdim  const PointerType* PT = T->getAs<PointerType>();
936263509Sdim  QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
937263509Sdim  if (UPointeeT->isRecordType()) {
938263509Sdim    const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
939263509Sdim    if (!RecordTy->getDecl()->isCompleteDefinition())
940263509Sdim      return false;
941263509Sdim  }
942263509Sdim  return true;
943263509Sdim}
944263509Sdim
945263509Sdim/// \brief Check whether the two versions match.
946263509Sdimstatic bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) {
947263509Sdim  return (X == Y);
948263509Sdim}
949263509Sdim
950263509Sdim/// AvailabilityAttrsMatch - This routine checks that if comparing two
951263509Sdim/// availability attributes, all their components match. It returns
952263509Sdim/// true, if not dealing with availability or when all components of
953263509Sdim/// availability attributes match. This routine is only called when
954263509Sdim/// the attributes are of the same kind.
955263509Sdimstatic bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
956263509Sdim  const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
957263509Sdim  if (!AA1)
958263509Sdim    return true;
959263509Sdim  const AvailabilityAttr *AA2 = dyn_cast<AvailabilityAttr>(At2);
960263509Sdim
961263509Sdim  VersionTuple Introduced1 = AA1->getIntroduced();
962263509Sdim  VersionTuple Deprecated1 = AA1->getDeprecated();
963263509Sdim  VersionTuple Obsoleted1 = AA1->getObsoleted();
964263509Sdim  bool IsUnavailable1 = AA1->getUnavailable();
965263509Sdim  VersionTuple Introduced2 = AA2->getIntroduced();
966263509Sdim  VersionTuple Deprecated2 = AA2->getDeprecated();
967263509Sdim  VersionTuple Obsoleted2 = AA2->getObsoleted();
968263509Sdim  bool IsUnavailable2 = AA2->getUnavailable();
969263509Sdim  return (versionsMatch(Introduced1, Introduced2) &&
970263509Sdim          versionsMatch(Deprecated1, Deprecated2) &&
971263509Sdim          versionsMatch(Obsoleted1, Obsoleted2) &&
972263509Sdim          IsUnavailable1 == IsUnavailable2);
973263509Sdim
974263509Sdim}
975263509Sdim
976263509Sdimstatic bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2,
977263509Sdim                                   bool &AvailabilityArgsMatch) {
978263509Sdim  // This list is very small, so this need not be optimized.
979263509Sdim  for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
980263509Sdim    bool match = false;
981263509Sdim    for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
982263509Sdim      // Matching attribute kind only. Except for Availabilty attributes,
983263509Sdim      // we are not getting into details of the attributes. For all practical purposes
984263509Sdim      // this is sufficient.
985263509Sdim      if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
986263509Sdim        if (AvailabilityArgsMatch)
987263509Sdim          AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]);
988263509Sdim        match = true;
989263509Sdim        break;
990263509Sdim      }
991263509Sdim    }
992263509Sdim    if (!match)
993263509Sdim      return false;
994263509Sdim  }
995263509Sdim  return true;
996263509Sdim}
997263509Sdim
998263509Sdim/// AttributesMatch - This routine checks list of attributes for two
999263509Sdim/// decls. It returns false, if there is a mismatch in kind of
1000263509Sdim/// attributes seen in the decls. It returns true if the two decls
1001263509Sdim/// have list of same kind of attributes. Furthermore, when there
1002263509Sdim/// are availability attributes in the two decls, it sets the
1003263509Sdim/// AvailabilityArgsMatch to false if availability attributes have
1004263509Sdim/// different versions, etc.
1005263509Sdimstatic bool AttributesMatch(const Decl *Decl1, const Decl *Decl2,
1006263509Sdim                            bool &AvailabilityArgsMatch) {
1007263509Sdim  if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) {
1008263509Sdim    AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs());
1009263509Sdim    return true;
1010263509Sdim  }
1011263509Sdim  AvailabilityArgsMatch = true;
1012263509Sdim  const AttrVec &Attrs1 = Decl1->getAttrs();
1013263509Sdim  const AttrVec &Attrs2 = Decl2->getAttrs();
1014263509Sdim  bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch);
1015263509Sdim  if (match && (Attrs2.size() > Attrs1.size()))
1016263509Sdim    return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch);
1017263509Sdim  return match;
1018263509Sdim}
1019263509Sdim
1020263509Sdimstatic bool IsValidIdentifier(ASTContext &Ctx,
1021263509Sdim                              const char *Name) {
1022263509Sdim  if (!isIdentifierHead(Name[0]))
1023263509Sdim    return false;
1024263509Sdim  std::string NameString = Name;
1025263509Sdim  NameString[0] = toLowercase(NameString[0]);
1026263509Sdim  IdentifierInfo *II = &Ctx.Idents.get(NameString);
1027263509Sdim  return II->getTokenID() ==  tok::identifier;
1028263509Sdim}
1029263509Sdim
1030263509Sdimbool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
1031263509Sdim                             ObjCContainerDecl *D,
1032263509Sdim                             ObjCMethodDecl *Method) {
1033263509Sdim  if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
1034263509Sdim      Method->param_size() != 0)
1035263509Sdim    return false;
1036263509Sdim  // Is this method candidate to be a getter?
1037263509Sdim  QualType GRT = Method->getResultType();
1038263509Sdim  if (GRT->isVoidType())
1039263509Sdim    return false;
1040263509Sdim
1041263509Sdim  Selector GetterSelector = Method->getSelector();
1042263509Sdim  ObjCInstanceTypeFamily OIT_Family =
1043263509Sdim    Selector::getInstTypeMethodFamily(GetterSelector);
1044263509Sdim
1045263509Sdim  if (OIT_Family != OIT_None)
1046263509Sdim    return false;
1047263509Sdim
1048263509Sdim  IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
1049263509Sdim  Selector SetterSelector =
1050263509Sdim  SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
1051263509Sdim                                         PP.getSelectorTable(),
1052263509Sdim                                         getterName);
1053263509Sdim  ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
1054263509Sdim  unsigned LengthOfPrefix = 0;
1055263509Sdim  if (!SetterMethod) {
1056263509Sdim    // try a different naming convention for getter: isXxxxx
1057263509Sdim    StringRef getterNameString = getterName->getName();
1058263509Sdim    bool IsPrefix = getterNameString.startswith("is");
1059263509Sdim    // Note that we don't want to change an isXXX method of retainable object
1060263509Sdim    // type to property (readonly or otherwise).
1061263509Sdim    if (IsPrefix && GRT->isObjCRetainableType())
1062263509Sdim      return false;
1063263509Sdim    if (IsPrefix || getterNameString.startswith("get")) {
1064263509Sdim      LengthOfPrefix = (IsPrefix ? 2 : 3);
1065263509Sdim      const char *CGetterName = getterNameString.data() + LengthOfPrefix;
1066263509Sdim      // Make sure that first character after "is" or "get" prefix can
1067263509Sdim      // start an identifier.
1068263509Sdim      if (!IsValidIdentifier(Ctx, CGetterName))
1069263509Sdim        return false;
1070263509Sdim      if (CGetterName[0] && isUppercase(CGetterName[0])) {
1071263509Sdim        getterName = &Ctx.Idents.get(CGetterName);
1072263509Sdim        SetterSelector =
1073263509Sdim        SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
1074263509Sdim                                               PP.getSelectorTable(),
1075263509Sdim                                               getterName);
1076263509Sdim        SetterMethod = D->getInstanceMethod(SetterSelector);
1077263509Sdim      }
1078263509Sdim    }
1079263509Sdim  }
1080263509Sdim
1081263509Sdim  if (SetterMethod) {
1082263509Sdim    if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
1083263509Sdim      return false;
1084263509Sdim    bool AvailabilityArgsMatch;
1085263509Sdim    if (SetterMethod->isDeprecated() ||
1086263509Sdim        !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch))
1087263509Sdim      return false;
1088263509Sdim
1089263509Sdim    // Is this a valid setter, matching the target getter?
1090263509Sdim    QualType SRT = SetterMethod->getResultType();
1091263509Sdim    if (!SRT->isVoidType())
1092263509Sdim      return false;
1093263509Sdim    const ParmVarDecl *argDecl = *SetterMethod->param_begin();
1094263509Sdim    QualType ArgType = argDecl->getType();
1095263509Sdim    if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
1096263509Sdim      return false;
1097263509Sdim    edit::Commit commit(*Editor);
1098263509Sdim    rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
1099263509Sdim                          LengthOfPrefix,
1100263509Sdim                          (ASTMigrateActions &
1101263509Sdim                           FrontendOptions::ObjCMT_AtomicProperty) != 0,
1102263509Sdim                          (ASTMigrateActions &
1103263509Sdim                           FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
1104263509Sdim                          AvailabilityArgsMatch);
1105263509Sdim    Editor->commit(commit);
1106263509Sdim    return true;
1107263509Sdim  }
1108263509Sdim  else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
1109263509Sdim    // Try a non-void method with no argument (and no setter or property of same name
1110263509Sdim    // as a 'readonly' property.
1111263509Sdim    edit::Commit commit(*Editor);
1112263509Sdim    rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
1113263509Sdim                          LengthOfPrefix,
1114263509Sdim                          (ASTMigrateActions &
1115263509Sdim                           FrontendOptions::ObjCMT_AtomicProperty) != 0,
1116263509Sdim                          (ASTMigrateActions &
1117263509Sdim                           FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
1118263509Sdim                          /*AvailabilityArgsMatch*/false);
1119263509Sdim    Editor->commit(commit);
1120263509Sdim    return true;
1121263509Sdim  }
1122263509Sdim  return false;
1123263509Sdim}
1124263509Sdim
1125263509Sdimvoid ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
1126263509Sdim                                                          ObjCMethodDecl *OM) {
1127263509Sdim  if (OM->isImplicit() ||
1128263509Sdim      !OM->isInstanceMethod() ||
1129263509Sdim      OM->hasAttr<ObjCReturnsInnerPointerAttr>())
1130263509Sdim    return;
1131263509Sdim
1132263509Sdim  QualType RT = OM->getResultType();
1133263509Sdim  if (!TypeIsInnerPointer(RT) ||
1134263509Sdim      !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
1135263509Sdim    return;
1136263509Sdim
1137263509Sdim  edit::Commit commit(*Editor);
1138263509Sdim  commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER");
1139263509Sdim  Editor->commit(commit);
1140263509Sdim}
1141263509Sdim
1142263509Sdimvoid ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
1143263509Sdim                                                                  ObjCPropertyDecl *P) {
1144263509Sdim  QualType T = P->getType();
1145263509Sdim
1146263509Sdim  if (!TypeIsInnerPointer(T) ||
1147263509Sdim      !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
1148263509Sdim    return;
1149263509Sdim  edit::Commit commit(*Editor);
1150263509Sdim  commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER ");
1151263509Sdim  Editor->commit(commit);
1152263509Sdim}
1153263509Sdim
1154263509Sdimvoid ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
1155263509Sdim                                                 ObjCContainerDecl *CDecl) {
1156263509Sdim  if (CDecl->isDeprecated())
1157263509Sdim    return;
1158263509Sdim
1159263509Sdim  // migrate methods which can have instancetype as their result type.
1160263509Sdim  for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
1161263509Sdim       MEnd = CDecl->meth_end();
1162263509Sdim       M != MEnd; ++M) {
1163263509Sdim    ObjCMethodDecl *Method = (*M);
1164263509Sdim    if (Method->isDeprecated())
1165263509Sdim      continue;
1166263509Sdim    migrateMethodInstanceType(Ctx, CDecl, Method);
1167263509Sdim  }
1168263509Sdim}
1169263509Sdim
1170263509Sdimvoid ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
1171263509Sdim                                                  ObjCContainerDecl *CDecl,
1172263509Sdim                                                  ObjCMethodDecl *OM,
1173263509Sdim                                                  ObjCInstanceTypeFamily OIT_Family) {
1174263509Sdim  if (OM->isInstanceMethod() ||
1175263509Sdim      OM->getResultType() == Ctx.getObjCInstanceType() ||
1176263509Sdim      !OM->getResultType()->isObjCIdType())
1177263509Sdim    return;
1178263509Sdim
1179263509Sdim  // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
1180263509Sdim  // NSYYYNamE with matching names be at least 3 characters long.
1181263509Sdim  ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1182263509Sdim  if (!IDecl) {
1183263509Sdim    if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1184263509Sdim      IDecl = CatDecl->getClassInterface();
1185263509Sdim    else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1186263509Sdim      IDecl = ImpDecl->getClassInterface();
1187263509Sdim  }
1188263509Sdim  if (!IDecl)
1189263509Sdim    return;
1190263509Sdim
1191263509Sdim  std::string StringClassName = IDecl->getName();
1192263509Sdim  StringRef LoweredClassName(StringClassName);
1193263509Sdim  std::string StringLoweredClassName = LoweredClassName.lower();
1194263509Sdim  LoweredClassName = StringLoweredClassName;
1195263509Sdim
1196263509Sdim  IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
1197263509Sdim  // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
1198263509Sdim  if (!MethodIdName)
1199263509Sdim    return;
1200263509Sdim
1201263509Sdim  std::string MethodName = MethodIdName->getName();
1202263509Sdim  if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
1203263509Sdim    StringRef STRefMethodName(MethodName);
1204263509Sdim    size_t len = 0;
1205263509Sdim    if (STRefMethodName.startswith("standard"))
1206263509Sdim      len = strlen("standard");
1207263509Sdim    else if (STRefMethodName.startswith("shared"))
1208263509Sdim      len = strlen("shared");
1209263509Sdim    else if (STRefMethodName.startswith("default"))
1210263509Sdim      len = strlen("default");
1211263509Sdim    else
1212263509Sdim      return;
1213263509Sdim    MethodName = STRefMethodName.substr(len);
1214263509Sdim  }
1215263509Sdim  std::string MethodNameSubStr = MethodName.substr(0, 3);
1216263509Sdim  StringRef MethodNamePrefix(MethodNameSubStr);
1217263509Sdim  std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
1218263509Sdim  MethodNamePrefix = StringLoweredMethodNamePrefix;
1219263509Sdim  size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
1220263509Sdim  if (Ix == StringRef::npos)
1221263509Sdim    return;
1222263509Sdim  std::string ClassNamePostfix = LoweredClassName.substr(Ix);
1223263509Sdim  StringRef LoweredMethodName(MethodName);
1224263509Sdim  std::string StringLoweredMethodName = LoweredMethodName.lower();
1225263509Sdim  LoweredMethodName = StringLoweredMethodName;
1226263509Sdim  if (!LoweredMethodName.startswith(ClassNamePostfix))
1227263509Sdim    return;
1228263509Sdim  if (OIT_Family == OIT_ReturnsSelf)
1229263509Sdim    ReplaceWithClasstype(*this, OM);
1230263509Sdim  else
1231263509Sdim    ReplaceWithInstancetype(*this, OM);
1232263509Sdim}
1233263509Sdim
1234263509Sdimstatic bool IsVoidStarType(QualType Ty) {
1235263509Sdim  if (!Ty->isPointerType())
1236263509Sdim    return false;
1237263509Sdim
1238263509Sdim  while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
1239263509Sdim    Ty = TD->getDecl()->getUnderlyingType();
1240263509Sdim
1241263509Sdim  // Is the type void*?
1242263509Sdim  const PointerType* PT = Ty->getAs<PointerType>();
1243263509Sdim  if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
1244263509Sdim    return true;
1245263509Sdim  return IsVoidStarType(PT->getPointeeType());
1246263509Sdim}
1247263509Sdim
1248263509Sdim/// AuditedType - This routine audits the type AT and returns false if it is one of known
1249263509Sdim/// CF object types or of the "void *" variety. It returns true if we don't care about the type
1250263509Sdim/// such as a non-pointer or pointers which have no ownership issues (such as "int *").
1251263509Sdimstatic bool AuditedType (QualType AT) {
1252263509Sdim  if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
1253263509Sdim    return true;
1254263509Sdim  // FIXME. There isn't much we can say about CF pointer type; or is there?
1255263509Sdim  if (ento::coreFoundation::isCFObjectRef(AT) ||
1256263509Sdim      IsVoidStarType(AT) ||
1257263509Sdim      // If an ObjC object is type, assuming that it is not a CF function and
1258263509Sdim      // that it is an un-audited function.
1259263509Sdim      AT->isObjCObjectPointerType() || AT->isObjCBuiltinType())
1260263509Sdim    return false;
1261263509Sdim  // All other pointers are assumed audited as harmless.
1262263509Sdim  return true;
1263263509Sdim}
1264263509Sdim
1265263509Sdimvoid ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
1266263509Sdim  if (CFFunctionIBCandidates.empty())
1267263509Sdim    return;
1268263509Sdim  if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
1269263509Sdim    CFFunctionIBCandidates.clear();
1270263509Sdim    FileId = FileID();
1271263509Sdim    return;
1272263509Sdim  }
1273263509Sdim  // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
1274263509Sdim  const Decl *FirstFD = CFFunctionIBCandidates[0];
1275263509Sdim  const Decl *LastFD  =
1276263509Sdim    CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
1277263509Sdim  const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
1278263509Sdim  edit::Commit commit(*Editor);
1279263509Sdim  commit.insertBefore(FirstFD->getLocStart(), PragmaString);
1280263509Sdim  PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
1281263509Sdim  SourceLocation EndLoc = LastFD->getLocEnd();
1282263509Sdim  // get location just past end of function location.
1283263509Sdim  EndLoc = PP.getLocForEndOfToken(EndLoc);
1284263509Sdim  if (isa<FunctionDecl>(LastFD)) {
1285263509Sdim    // For Methods, EndLoc points to the ending semcolon. So,
1286263509Sdim    // not of these extra work is needed.
1287263509Sdim    Token Tok;
1288263509Sdim    // get locaiton of token that comes after end of function.
1289263509Sdim    bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
1290263509Sdim    if (!Failed)
1291263509Sdim      EndLoc = Tok.getLocation();
1292263509Sdim  }
1293263509Sdim  commit.insertAfterToken(EndLoc, PragmaString);
1294263509Sdim  Editor->commit(commit);
1295263509Sdim  FileId = FileID();
1296263509Sdim  CFFunctionIBCandidates.clear();
1297263509Sdim}
1298263509Sdim
1299263509Sdimvoid ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
1300263509Sdim  if (Decl->isDeprecated())
1301263509Sdim    return;
1302263509Sdim
1303263509Sdim  if (Decl->hasAttr<CFAuditedTransferAttr>()) {
1304263509Sdim    assert(CFFunctionIBCandidates.empty() &&
1305263509Sdim           "Cannot have audited functions/methods inside user "
1306263509Sdim           "provided CF_IMPLICIT_BRIDGING_ENABLE");
1307263509Sdim    return;
1308263509Sdim  }
1309263509Sdim
1310263509Sdim  // Finction must be annotated first.
1311263509Sdim  if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
1312263509Sdim    CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
1313263509Sdim    if (AuditKind == CF_BRIDGING_ENABLE) {
1314263509Sdim      CFFunctionIBCandidates.push_back(Decl);
1315263509Sdim      if (FileId.isInvalid())
1316263509Sdim        FileId = PP.getSourceManager().getFileID(Decl->getLocation());
1317263509Sdim    }
1318263509Sdim    else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
1319263509Sdim      if (!CFFunctionIBCandidates.empty()) {
1320263509Sdim        CFFunctionIBCandidates.push_back(Decl);
1321263509Sdim        if (FileId.isInvalid())
1322263509Sdim          FileId = PP.getSourceManager().getFileID(Decl->getLocation());
1323263509Sdim      }
1324263509Sdim    }
1325263509Sdim    else
1326263509Sdim      AnnotateImplicitBridging(Ctx);
1327263509Sdim  }
1328263509Sdim  else {
1329263509Sdim    migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
1330263509Sdim    AnnotateImplicitBridging(Ctx);
1331263509Sdim  }
1332263509Sdim}
1333263509Sdim
1334263509Sdimvoid ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1335263509Sdim                                              const CallEffects &CE,
1336263509Sdim                                              const FunctionDecl *FuncDecl,
1337263509Sdim                                              bool ResultAnnotated) {
1338263509Sdim  // Annotate function.
1339263509Sdim  if (!ResultAnnotated) {
1340263509Sdim    RetEffect Ret = CE.getReturnValue();
1341263509Sdim    const char *AnnotationString = 0;
1342263509Sdim    if (Ret.getObjKind() == RetEffect::CF) {
1343263509Sdim      if (Ret.isOwned() &&
1344263509Sdim          Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
1345263509Sdim        AnnotationString = " CF_RETURNS_RETAINED";
1346263509Sdim      else if (Ret.notOwned() &&
1347263509Sdim               Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
1348263509Sdim        AnnotationString = " CF_RETURNS_NOT_RETAINED";
1349263509Sdim    }
1350263509Sdim    else if (Ret.getObjKind() == RetEffect::ObjC) {
1351263509Sdim      if (Ret.isOwned() &&
1352263509Sdim          Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
1353263509Sdim        AnnotationString = " NS_RETURNS_RETAINED";
1354263509Sdim    }
1355263509Sdim
1356263509Sdim    if (AnnotationString) {
1357263509Sdim      edit::Commit commit(*Editor);
1358263509Sdim      commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString);
1359263509Sdim      Editor->commit(commit);
1360263509Sdim    }
1361263509Sdim  }
1362263509Sdim  llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1363263509Sdim  unsigned i = 0;
1364263509Sdim  for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1365263509Sdim       pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1366263509Sdim    const ParmVarDecl *pd = *pi;
1367263509Sdim    ArgEffect AE = AEArgs[i];
1368263509Sdim    if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
1369263509Sdim        Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
1370263509Sdim      edit::Commit commit(*Editor);
1371263509Sdim      commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1372263509Sdim      Editor->commit(commit);
1373263509Sdim    }
1374263509Sdim    else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() &&
1375263509Sdim             Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) {
1376263509Sdim      edit::Commit commit(*Editor);
1377263509Sdim      commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
1378263509Sdim      Editor->commit(commit);
1379263509Sdim    }
1380263509Sdim  }
1381263509Sdim}
1382263509Sdim
1383263509Sdim
1384263509SdimObjCMigrateASTConsumer::CF_BRIDGING_KIND
1385263509Sdim  ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
1386263509Sdim                                                  ASTContext &Ctx,
1387263509Sdim                                                  const FunctionDecl *FuncDecl) {
1388263509Sdim  if (FuncDecl->hasBody())
1389263509Sdim    return CF_BRIDGING_NONE;
1390263509Sdim
1391263509Sdim  CallEffects CE  = CallEffects::getEffect(FuncDecl);
1392263509Sdim  bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
1393263509Sdim                                FuncDecl->getAttr<CFReturnsNotRetainedAttr>() ||
1394263509Sdim                                FuncDecl->getAttr<NSReturnsRetainedAttr>() ||
1395263509Sdim                                FuncDecl->getAttr<NSReturnsNotRetainedAttr>() ||
1396263509Sdim                                FuncDecl->getAttr<NSReturnsAutoreleasedAttr>());
1397263509Sdim
1398263509Sdim  // Trivial case of when funciton is annotated and has no argument.
1399263509Sdim  if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
1400263509Sdim    return CF_BRIDGING_NONE;
1401263509Sdim
1402263509Sdim  bool ReturnCFAudited = false;
1403263509Sdim  if (!FuncIsReturnAnnotated) {
1404263509Sdim    RetEffect Ret = CE.getReturnValue();
1405263509Sdim    if (Ret.getObjKind() == RetEffect::CF &&
1406263509Sdim        (Ret.isOwned() || Ret.notOwned()))
1407263509Sdim      ReturnCFAudited = true;
1408263509Sdim    else if (!AuditedType(FuncDecl->getResultType()))
1409263509Sdim      return CF_BRIDGING_NONE;
1410263509Sdim  }
1411263509Sdim
1412263509Sdim  // At this point result type is audited for potential inclusion.
1413263509Sdim  // Now, how about argument types.
1414263509Sdim  llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1415263509Sdim  unsigned i = 0;
1416263509Sdim  bool ArgCFAudited = false;
1417263509Sdim  for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1418263509Sdim       pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1419263509Sdim    const ParmVarDecl *pd = *pi;
1420263509Sdim    ArgEffect AE = AEArgs[i];
1421263509Sdim    if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
1422263509Sdim      if (AE == DecRef && !pd->getAttr<CFConsumedAttr>())
1423263509Sdim        ArgCFAudited = true;
1424263509Sdim      else if (AE == IncRef)
1425263509Sdim        ArgCFAudited = true;
1426263509Sdim    }
1427263509Sdim    else {
1428263509Sdim      QualType AT = pd->getType();
1429263509Sdim      if (!AuditedType(AT)) {
1430263509Sdim        AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated);
1431263509Sdim        return CF_BRIDGING_NONE;
1432263509Sdim      }
1433263509Sdim    }
1434263509Sdim  }
1435263509Sdim  if (ReturnCFAudited || ArgCFAudited)
1436263509Sdim    return CF_BRIDGING_ENABLE;
1437263509Sdim
1438263509Sdim  return CF_BRIDGING_MAY_INCLUDE;
1439263509Sdim}
1440263509Sdim
1441263509Sdimvoid ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
1442263509Sdim                                                 ObjCContainerDecl *CDecl) {
1443263509Sdim  if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated())
1444263509Sdim    return;
1445263509Sdim
1446263509Sdim  // migrate methods which can have instancetype as their result type.
1447263509Sdim  for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
1448263509Sdim       MEnd = CDecl->meth_end();
1449263509Sdim       M != MEnd; ++M) {
1450263509Sdim    ObjCMethodDecl *Method = (*M);
1451263509Sdim    migrateCFAnnotation(Ctx, Method);
1452263509Sdim  }
1453263509Sdim}
1454263509Sdim
1455263509Sdimvoid ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1456263509Sdim                                              const CallEffects &CE,
1457263509Sdim                                              const ObjCMethodDecl *MethodDecl,
1458263509Sdim                                              bool ResultAnnotated) {
1459263509Sdim  // Annotate function.
1460263509Sdim  if (!ResultAnnotated) {
1461263509Sdim    RetEffect Ret = CE.getReturnValue();
1462263509Sdim    const char *AnnotationString = 0;
1463263509Sdim    if (Ret.getObjKind() == RetEffect::CF) {
1464263509Sdim      if (Ret.isOwned() &&
1465263509Sdim          Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
1466263509Sdim        AnnotationString = " CF_RETURNS_RETAINED";
1467263509Sdim      else if (Ret.notOwned() &&
1468263509Sdim               Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
1469263509Sdim        AnnotationString = " CF_RETURNS_NOT_RETAINED";
1470263509Sdim    }
1471263509Sdim    else if (Ret.getObjKind() == RetEffect::ObjC) {
1472263509Sdim      ObjCMethodFamily OMF = MethodDecl->getMethodFamily();
1473263509Sdim      switch (OMF) {
1474263509Sdim        case clang::OMF_alloc:
1475263509Sdim        case clang::OMF_new:
1476263509Sdim        case clang::OMF_copy:
1477263509Sdim        case clang::OMF_init:
1478263509Sdim        case clang::OMF_mutableCopy:
1479263509Sdim          break;
1480263509Sdim
1481263509Sdim        default:
1482263509Sdim          if (Ret.isOwned() &&
1483263509Sdim              Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
1484263509Sdim            AnnotationString = " NS_RETURNS_RETAINED";
1485263509Sdim          break;
1486263509Sdim      }
1487263509Sdim    }
1488263509Sdim
1489263509Sdim    if (AnnotationString) {
1490263509Sdim      edit::Commit commit(*Editor);
1491263509Sdim      commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
1492263509Sdim      Editor->commit(commit);
1493263509Sdim    }
1494263509Sdim  }
1495263509Sdim  llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1496263509Sdim  unsigned i = 0;
1497263509Sdim  for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1498263509Sdim       pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1499263509Sdim    const ParmVarDecl *pd = *pi;
1500263509Sdim    ArgEffect AE = AEArgs[i];
1501263509Sdim    if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
1502263509Sdim        Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
1503263509Sdim      edit::Commit commit(*Editor);
1504263509Sdim      commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1505263509Sdim      Editor->commit(commit);
1506263509Sdim    }
1507263509Sdim  }
1508263509Sdim}
1509263509Sdim
1510263509Sdimvoid ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
1511263509Sdim                                            ASTContext &Ctx,
1512263509Sdim                                            const ObjCMethodDecl *MethodDecl) {
1513263509Sdim  if (MethodDecl->hasBody() || MethodDecl->isImplicit())
1514263509Sdim    return;
1515263509Sdim
1516263509Sdim  CallEffects CE  = CallEffects::getEffect(MethodDecl);
1517263509Sdim  bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
1518263509Sdim                                  MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
1519263509Sdim                                  MethodDecl->getAttr<NSReturnsRetainedAttr>() ||
1520263509Sdim                                  MethodDecl->getAttr<NSReturnsNotRetainedAttr>() ||
1521263509Sdim                                  MethodDecl->getAttr<NSReturnsAutoreleasedAttr>());
1522263509Sdim
1523263509Sdim  if (CE.getReceiver() ==  DecRefMsg &&
1524263509Sdim      !MethodDecl->getAttr<NSConsumesSelfAttr>() &&
1525263509Sdim      MethodDecl->getMethodFamily() != OMF_init &&
1526263509Sdim      MethodDecl->getMethodFamily() != OMF_release &&
1527263509Sdim      Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) {
1528263509Sdim    edit::Commit commit(*Editor);
1529263509Sdim    commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF");
1530263509Sdim    Editor->commit(commit);
1531263509Sdim  }
1532263509Sdim
1533263509Sdim  // Trivial case of when funciton is annotated and has no argument.
1534263509Sdim  if (MethodIsReturnAnnotated &&
1535263509Sdim      (MethodDecl->param_begin() == MethodDecl->param_end()))
1536263509Sdim    return;
1537263509Sdim
1538263509Sdim  if (!MethodIsReturnAnnotated) {
1539263509Sdim    RetEffect Ret = CE.getReturnValue();
1540263509Sdim    if ((Ret.getObjKind() == RetEffect::CF ||
1541263509Sdim         Ret.getObjKind() == RetEffect::ObjC) &&
1542263509Sdim        (Ret.isOwned() || Ret.notOwned())) {
1543263509Sdim      AddCFAnnotations(Ctx, CE, MethodDecl, false);
1544263509Sdim      return;
1545263509Sdim    }
1546263509Sdim    else if (!AuditedType(MethodDecl->getResultType()))
1547263509Sdim      return;
1548263509Sdim  }
1549263509Sdim
1550263509Sdim  // At this point result type is either annotated or audited.
1551263509Sdim  // Now, how about argument types.
1552263509Sdim  llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1553263509Sdim  unsigned i = 0;
1554263509Sdim  for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1555263509Sdim       pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1556263509Sdim    const ParmVarDecl *pd = *pi;
1557263509Sdim    ArgEffect AE = AEArgs[i];
1558263509Sdim    if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef ||
1559263509Sdim        !AuditedType(pd->getType())) {
1560263509Sdim      AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
1561263509Sdim      return;
1562263509Sdim    }
1563263509Sdim  }
1564263509Sdim  return;
1565263509Sdim}
1566263509Sdim
1567234287Sdimnamespace {
1568234287Sdim
1569234287Sdimclass RewritesReceiver : public edit::EditsReceiver {
1570234287Sdim  Rewriter &Rewrite;
1571234287Sdim
1572234287Sdimpublic:
1573234287Sdim  RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
1574234287Sdim
1575234287Sdim  virtual void insert(SourceLocation loc, StringRef text) {
1576234287Sdim    Rewrite.InsertText(loc, text);
1577234287Sdim  }
1578234287Sdim  virtual void replace(CharSourceRange range, StringRef text) {
1579234287Sdim    Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
1580234287Sdim  }
1581234287Sdim};
1582234287Sdim
1583234287Sdim}
1584234287Sdim
1585263509Sdimstatic bool
1586263509SdimIsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) {
1587263509Sdim  bool Invalid = false;
1588263509Sdim  const SrcMgr::SLocEntry &SEntry =
1589263509Sdim  Ctx.getSourceManager().getSLocEntry(FID, &Invalid);
1590263509Sdim  if (!Invalid && SEntry.isFile()) {
1591263509Sdim    const SrcMgr::FileInfo &FI = SEntry.getFile();
1592263509Sdim    if (!FI.hasLineDirectives()) {
1593263509Sdim      if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem)
1594263509Sdim        return true;
1595263509Sdim      if (FI.getFileCharacteristic() == SrcMgr::C_System) {
1596263509Sdim        // This file is in a system header directory. Continue with commiting change
1597263509Sdim        // only if it is a user specified system directory because user put a
1598263509Sdim        // .system_framework file in the framework directory.
1599263509Sdim        StringRef Directory(file->getDir()->getName());
1600263509Sdim        size_t Ix = Directory.rfind(".framework");
1601263509Sdim        if (Ix == StringRef::npos)
1602263509Sdim          return true;
1603263509Sdim        std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework"));
1604263509Sdim        PatchToSystemFramework += ".system_framework";
1605263509Sdim        if (!llvm::sys::fs::exists(PatchToSystemFramework.data()))
1606263509Sdim          return true;
1607263509Sdim      }
1608263509Sdim    }
1609263509Sdim  }
1610263509Sdim  return false;
1611263509Sdim}
1612263509Sdim
1613234287Sdimvoid ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
1614263509Sdim
1615263509Sdim  TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
1616263509Sdim  if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) {
1617263509Sdim    for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
1618263509Sdim         D != DEnd; ++D) {
1619263509Sdim      FileID FID = PP.getSourceManager().getFileID((*D)->getLocation());
1620263509Sdim      if (!FID.isInvalid())
1621263509Sdim        if (!FileId.isInvalid() && FileId != FID) {
1622263509Sdim          if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1623263509Sdim            AnnotateImplicitBridging(Ctx);
1624263509Sdim        }
1625263509Sdim
1626263509Sdim      if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
1627263509Sdim        migrateObjCInterfaceDecl(Ctx, CDecl);
1628263509Sdim      if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
1629263509Sdim        migrateObjCInterfaceDecl(Ctx, CatDecl);
1630263509Sdim        if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1631263509Sdim          migrateDeprecatedAnnotation(Ctx, CatDecl);
1632263509Sdim      }
1633263509Sdim      else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
1634263509Sdim        ObjCProtocolDecls.insert(PDecl);
1635263509Sdim      else if (const ObjCImplementationDecl *ImpDecl =
1636263509Sdim               dyn_cast<ObjCImplementationDecl>(*D)) {
1637263509Sdim        if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance)
1638263509Sdim          migrateProtocolConformance(Ctx, ImpDecl);
1639263509Sdim      }
1640263509Sdim      else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
1641263509Sdim        if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
1642263509Sdim          continue;
1643263509Sdim        DeclContext::decl_iterator N = D;
1644263509Sdim        if (++N != DEnd) {
1645263509Sdim          const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
1646263509Sdim          if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
1647263509Sdim            D++;
1648263509Sdim        }
1649263509Sdim        else
1650263509Sdim          migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0);
1651263509Sdim      }
1652263509Sdim      else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
1653263509Sdim        if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
1654263509Sdim          continue;
1655263509Sdim        DeclContext::decl_iterator N = D;
1656263509Sdim        if (++N == DEnd)
1657263509Sdim          continue;
1658263509Sdim        if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
1659263509Sdim          if (++N != DEnd)
1660263509Sdim            if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
1661263509Sdim              // prefer typedef-follows-enum to enum-follows-typedef pattern.
1662263509Sdim              if (migrateNSEnumDecl(Ctx, ED, TDF)) {
1663263509Sdim                ++D; ++D;
1664263509Sdim                CacheObjCNSIntegerTypedefed(TD);
1665263509Sdim                continue;
1666263509Sdim              }
1667263509Sdim            }
1668263509Sdim          if (migrateNSEnumDecl(Ctx, ED, TD)) {
1669263509Sdim            ++D;
1670263509Sdim            continue;
1671263509Sdim          }
1672263509Sdim        }
1673263509Sdim        CacheObjCNSIntegerTypedefed(TD);
1674263509Sdim      }
1675263509Sdim      else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
1676263509Sdim        if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1677263509Sdim          migrateCFAnnotation(Ctx, FD);
1678263509Sdim      }
1679263509Sdim
1680263509Sdim      if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
1681263509Sdim        // migrate methods which can have instancetype as their result type.
1682263509Sdim        if (ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype)
1683263509Sdim          migrateAllMethodInstaceType(Ctx, CDecl);
1684263509Sdim        // annotate methods with CF annotations.
1685263509Sdim        if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1686263509Sdim          migrateARCSafeAnnotation(Ctx, CDecl);
1687263509Sdim      }
1688263509Sdim    }
1689263509Sdim    if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1690263509Sdim      AnnotateImplicitBridging(Ctx);
1691263509Sdim  }
1692263509Sdim
1693234287Sdim  Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
1694234287Sdim  RewritesReceiver Rec(rewriter);
1695234287Sdim  Editor->applyRewrites(Rec);
1696234287Sdim
1697234287Sdim  for (Rewriter::buffer_iterator
1698234287Sdim        I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
1699234287Sdim    FileID FID = I->first;
1700234287Sdim    RewriteBuffer &buf = I->second;
1701234287Sdim    const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
1702234287Sdim    assert(file);
1703263509Sdim    if (IsReallyASystemHeader(Ctx, file, FID))
1704263509Sdim      continue;
1705263509Sdim    if (!canModifyFile(file->getName()))
1706263509Sdim      continue;
1707252723Sdim    SmallString<512> newText;
1708234287Sdim    llvm::raw_svector_ostream vecOS(newText);
1709234287Sdim    buf.write(vecOS);
1710234287Sdim    vecOS.flush();
1711234287Sdim    llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
1712234287Sdim                   StringRef(newText.data(), newText.size()), file->getName());
1713252723Sdim    SmallString<64> filePath(file->getName());
1714234287Sdim    FileMgr.FixupRelativePath(filePath);
1715234287Sdim    Remapper.remap(filePath.str(), memBuf);
1716234287Sdim  }
1717234287Sdim
1718234287Sdim  if (IsOutputFile) {
1719234287Sdim    Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
1720234287Sdim  } else {
1721234287Sdim    Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
1722234287Sdim  }
1723234287Sdim}
1724234287Sdim
1725234287Sdimbool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
1726245431Sdim  CI.getDiagnostics().setIgnoreAllWarnings(true);
1727234287Sdim  return true;
1728234287Sdim}
1729234287Sdim
1730263509Sdimstatic std::vector<std::string> getWhiteListFilenames(StringRef DirPath) {
1731263509Sdim  using namespace llvm::sys::fs;
1732263509Sdim  using namespace llvm::sys::path;
1733263509Sdim
1734263509Sdim  std::vector<std::string> Filenames;
1735263509Sdim  if (DirPath.empty() || !is_directory(DirPath))
1736263509Sdim    return Filenames;
1737263509Sdim
1738263509Sdim  llvm::error_code EC;
1739263509Sdim  directory_iterator DI = directory_iterator(DirPath, EC);
1740263509Sdim  directory_iterator DE;
1741263509Sdim  for (; !EC && DI != DE; DI = DI.increment(EC)) {
1742263509Sdim    if (is_regular_file(DI->path()))
1743263509Sdim      Filenames.push_back(filename(DI->path()));
1744263509Sdim  }
1745263509Sdim
1746263509Sdim  return Filenames;
1747263509Sdim}
1748263509Sdim
1749234287SdimASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
1750234287Sdim                                                  StringRef InFile) {
1751252723Sdim  PPConditionalDirectiveRecord *
1752252723Sdim    PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
1753263509Sdim  unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
1754263509Sdim  unsigned ObjCMTOpts = ObjCMTAction;
1755263509Sdim  // These are companion flags, they do not enable transformations.
1756263509Sdim  ObjCMTOpts &= ~(FrontendOptions::ObjCMT_AtomicProperty |
1757263509Sdim                  FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty);
1758263509Sdim  if (ObjCMTOpts == FrontendOptions::ObjCMT_None) {
1759263509Sdim    // If no specific option was given, enable literals+subscripting transforms
1760263509Sdim    // by default.
1761263509Sdim    ObjCMTAction |= FrontendOptions::ObjCMT_Literals |
1762263509Sdim                    FrontendOptions::ObjCMT_Subscripting;
1763263509Sdim  }
1764252723Sdim  CI.getPreprocessor().addPPCallbacks(PPRec);
1765263509Sdim  std::vector<std::string> WhiteList =
1766263509Sdim    getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath);
1767234287Sdim  return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
1768263509Sdim                                    ObjCMTAction,
1769234287Sdim                                    Remapper,
1770234287Sdim                                    CI.getFileManager(),
1771252723Sdim                                    PPRec,
1772263509Sdim                                    CI.getPreprocessor(),
1773263509Sdim                                    /*isOutputFile=*/true,
1774263509Sdim                                    WhiteList);
1775234287Sdim}
1776