blob: 05a81393eabfa5b81517cd21dd995702eba51850 [file] [log] [blame]
Ted Kremenekf7639e12012-03-06 20:06:33 +00001//===--- 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
Fariborz Jahanian85e988b2013-07-18 22:17:33 +000010#include "Transforms.h"
Ted Kremenekf7639e12012-03-06 20:06:33 +000011#include "clang/ARCMigrate/ARCMTActions.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000012#include "clang/AST/ASTConsumer.h"
13#include "clang/AST/ASTContext.h"
14#include "clang/AST/NSAPI.h"
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +000015#include "clang/AST/ParentMap.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000016#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"
Ted Kremenekf7639e12012-03-06 20:06:33 +000022#include "clang/Frontend/CompilerInstance.h"
23#include "clang/Frontend/MultiplexConsumer.h"
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +000024#include "clang/Lex/PPConditionalDirectiveRecord.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000025#include "clang/Lex/Preprocessor.h"
26#include "clang/Rewrite/Core/Rewriter.h"
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000027#include "clang/AST/Attr.h"
Ted Kremenekf7639e12012-03-06 20:06:33 +000028#include "llvm/ADT/SmallString.h"
29
30using namespace clang;
31using namespace arcmt;
32
33namespace {
34
35class ObjCMigrateASTConsumer : public ASTConsumer {
36 void migrateDecl(Decl *D);
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000037 void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCInterfaceDecl *D);
Fariborz Jahanian1be01532013-07-12 22:32:19 +000038 void migrateProtocolConformance(ASTContext &Ctx,
39 const ObjCImplementationDecl *ImpDecl);
Fariborz Jahanian92463272013-07-18 20:11:45 +000040 void migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
41 const TypedefDecl *TypedefDcl);
Fariborz Jahanian71221352013-07-23 22:42:28 +000042 void migrateInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
Fariborz Jahanian670ef262013-07-23 23:34:42 +000043 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
44 ObjCMethodDecl *OM);
Fariborz Jahanianc4291852013-08-02 18:00:53 +000045 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
Fariborz Jahanian9275c682013-08-02 20:54:18 +000046 ObjCMethodDecl *OM,
47 ObjCInstanceTypeFamily OIT_Family = OIT_None);
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000048
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +000049 void migrateFunctionDeclAnnotation(ASTContext &Ctx,
50 const FunctionDecl *FuncDecl);
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000051
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +000052 void migrateObjCMethodDeclAnnotation(ASTContext &Ctx,
53 const ObjCMethodDecl *MethodDecl);
Ted Kremenekf7639e12012-03-06 20:06:33 +000054public:
55 std::string MigrateDir;
56 bool MigrateLiterals;
57 bool MigrateSubscripting;
Fariborz Jahaniand83ef842013-07-09 16:59:14 +000058 bool MigrateProperty;
Dmitri Gribenkof8579502013-01-12 19:30:44 +000059 OwningPtr<NSAPI> NSAPIObj;
60 OwningPtr<edit::EditedSource> Editor;
Ted Kremenekf7639e12012-03-06 20:06:33 +000061 FileRemapper &Remapper;
62 FileManager &FileMgr;
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +000063 const PPConditionalDirectiveRecord *PPRec;
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000064 Preprocessor &PP;
Ted Kremenekf7639e12012-03-06 20:06:33 +000065 bool IsOutputFile;
Fariborz Jahanian1be01532013-07-12 22:32:19 +000066 llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
67
Ted Kremenekf7639e12012-03-06 20:06:33 +000068 ObjCMigrateASTConsumer(StringRef migrateDir,
69 bool migrateLiterals,
70 bool migrateSubscripting,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +000071 bool migrateProperty,
Ted Kremenekf7639e12012-03-06 20:06:33 +000072 FileRemapper &remapper,
73 FileManager &fileMgr,
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +000074 const PPConditionalDirectiveRecord *PPRec,
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000075 Preprocessor &PP,
Ted Kremenekf7639e12012-03-06 20:06:33 +000076 bool isOutputFile = false)
77 : MigrateDir(migrateDir),
78 MigrateLiterals(migrateLiterals),
79 MigrateSubscripting(migrateSubscripting),
Fariborz Jahaniand83ef842013-07-09 16:59:14 +000080 MigrateProperty(migrateProperty),
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000081 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
Ted Kremenekf7639e12012-03-06 20:06:33 +000082 IsOutputFile(isOutputFile) { }
83
84protected:
85 virtual void Initialize(ASTContext &Context) {
86 NSAPIObj.reset(new NSAPI(Context));
87 Editor.reset(new edit::EditedSource(Context.getSourceManager(),
David Blaikiebbafb8a2012-03-11 07:00:24 +000088 Context.getLangOpts(),
Ted Kremenekf7639e12012-03-06 20:06:33 +000089 PPRec));
90 }
91
92 virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
93 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
94 migrateDecl(*I);
95 return true;
96 }
97 virtual void HandleInterestingDecl(DeclGroupRef DG) {
98 // Ignore decls from the PCH.
99 }
100 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
101 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
102 }
103
104 virtual void HandleTranslationUnit(ASTContext &Ctx);
105};
106
107}
108
109ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
110 StringRef migrateDir,
111 bool migrateLiterals,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000112 bool migrateSubscripting,
113 bool migrateProperty)
Ted Kremenekf7639e12012-03-06 20:06:33 +0000114 : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
115 MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000116 MigrateProperty(migrateProperty),
Ted Kremenekf7639e12012-03-06 20:06:33 +0000117 CompInst(0) {
118 if (MigrateDir.empty())
119 MigrateDir = "."; // user current directory if none is given.
120}
121
122ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
123 StringRef InFile) {
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +0000124 PPConditionalDirectiveRecord *
125 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
126 CompInst->getPreprocessor().addPPCallbacks(PPRec);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000127 ASTConsumer *
128 WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
129 ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
130 MigrateLiterals,
131 MigrateSubscripting,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000132 MigrateProperty,
Ted Kremenekf7639e12012-03-06 20:06:33 +0000133 Remapper,
134 CompInst->getFileManager(),
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000135 PPRec,
136 CompInst->getPreprocessor());
Ted Kremenekf7639e12012-03-06 20:06:33 +0000137 ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
138 return new MultiplexConsumer(Consumers);
139}
140
141bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
142 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
143 /*ignoreIfFilesChanges=*/true);
144 CompInst = &CI;
145 CI.getDiagnostics().setIgnoreAllWarnings(true);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000146 return true;
147}
148
149namespace {
150class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
151 ObjCMigrateASTConsumer &Consumer;
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000152 ParentMap &PMap;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000153
154public:
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000155 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
156 : Consumer(consumer), PMap(PMap) { }
Ted Kremenekf7639e12012-03-06 20:06:33 +0000157
158 bool shouldVisitTemplateInstantiations() const { return false; }
159 bool shouldWalkTypesOfTypeLocs() const { return false; }
160
161 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
162 if (Consumer.MigrateLiterals) {
163 edit::Commit commit(*Consumer.Editor);
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000164 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000165 Consumer.Editor->commit(commit);
166 }
167
168 if (Consumer.MigrateSubscripting) {
169 edit::Commit commit(*Consumer.Editor);
170 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
171 Consumer.Editor->commit(commit);
172 }
173
174 return true;
175 }
176
177 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
178 // Do depth first; we want to rewrite the subexpressions first so that if
179 // we have to move expressions we will move them already rewritten.
180 for (Stmt::child_range range = E->children(); range; ++range)
181 if (!TraverseStmt(*range))
182 return false;
183
184 return WalkUpFromObjCMessageExpr(E);
185 }
186};
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000187
188class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
189 ObjCMigrateASTConsumer &Consumer;
190 OwningPtr<ParentMap> PMap;
191
192public:
193 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
194
195 bool shouldVisitTemplateInstantiations() const { return false; }
196 bool shouldWalkTypesOfTypeLocs() const { return false; }
197
198 bool TraverseStmt(Stmt *S) {
199 PMap.reset(new ParentMap(S));
200 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
201 return true;
202 }
203};
Ted Kremenekf7639e12012-03-06 20:06:33 +0000204}
205
206void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
207 if (!D)
208 return;
209 if (isa<ObjCMethodDecl>(D))
210 return; // Wait for the ObjC container declaration.
211
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000212 BodyMigrator(*this).TraverseDecl(D);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000213}
214
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000215static void append_attr(std::string &PropertyString, const char *attr,
216 bool GetterHasIsPrefix) {
217 PropertyString += (GetterHasIsPrefix ? ", " : "(");
218 PropertyString += attr;
219 PropertyString += ')';
220}
221
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000222static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter,
223 const ObjCMethodDecl *Setter,
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000224 const NSAPI &NS, edit::Commit &commit,
225 bool GetterHasIsPrefix) {
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000226 ASTContext &Context = NS.getASTContext();
227 std::string PropertyString = "@property";
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000228 std::string PropertyNameString = Getter->getNameAsString();
229 StringRef PropertyName(PropertyNameString);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000230 if (GetterHasIsPrefix) {
231 PropertyString += "(getter=";
232 PropertyString += PropertyNameString;
233 }
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000234 // Short circuit properties that contain the name "delegate" or "dataSource",
235 // or have exact name "target" to have unsafe_unretained attribute.
236 if (PropertyName.equals("target") ||
237 (PropertyName.find("delegate") != StringRef::npos) ||
238 (PropertyName.find("dataSource") != StringRef::npos))
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000239 append_attr(PropertyString, "unsafe_unretained", GetterHasIsPrefix);
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000240 else {
241 const ParmVarDecl *argDecl = *Setter->param_begin();
242 QualType ArgType = Context.getCanonicalType(argDecl->getType());
243 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
244 bool RetainableObject = ArgType->isObjCRetainableType();
245 if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
246 if (const ObjCObjectPointerType *ObjPtrTy =
247 ArgType->getAs<ObjCObjectPointerType>()) {
248 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
249 if (IDecl &&
250 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000251 append_attr(PropertyString, "copy", GetterHasIsPrefix);
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000252 else
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000253 append_attr(PropertyString, "retain", GetterHasIsPrefix);
254 } else if (GetterHasIsPrefix)
255 PropertyString += ')';
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000256 } else if (propertyLifetime == Qualifiers::OCL_Weak)
257 // TODO. More precise determination of 'weak' attribute requires
258 // looking into setter's implementation for backing weak ivar.
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000259 append_attr(PropertyString, "weak", GetterHasIsPrefix);
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000260 else if (RetainableObject)
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000261 append_attr(PropertyString, "retain", GetterHasIsPrefix);
262 else if (GetterHasIsPrefix)
263 PropertyString += ')';
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000264 }
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000265
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000266 QualType RT = Getter->getResultType();
267 if (!isa<TypedefType>(RT)) {
268 // strip off any ARC lifetime qualifier.
269 QualType CanResultTy = Context.getCanonicalType(RT);
270 if (CanResultTy.getQualifiers().hasObjCLifetime()) {
271 Qualifiers Qs = CanResultTy.getQualifiers();
272 Qs.removeObjCLifetime();
273 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
274 }
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000275 }
276 PropertyString += " ";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000277 PropertyString += RT.getAsString(Context.getPrintingPolicy());
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000278 PropertyString += " ";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000279 if (GetterHasIsPrefix) {
280 // property name must strip off "is" and lower case the first character
281 // after that; e.g. isContinuous will become continuous.
282 StringRef PropertyNameStringRef(PropertyNameString);
283 PropertyNameStringRef = PropertyNameStringRef.drop_front(2);
284 PropertyNameString = PropertyNameStringRef;
285 std::string NewPropertyNameString = PropertyNameString;
Fariborz Jahaniandb8bf832013-08-08 21:51:06 +0000286 NewPropertyNameString[0] = toLowercase(NewPropertyNameString[0]);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000287 PropertyString += NewPropertyNameString;
288 }
289 else
290 PropertyString += PropertyNameString;
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000291 commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
292 Getter->getDeclaratorEndLoc()),
293 PropertyString);
294 SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
295 // Get location past ';'
296 EndLoc = EndLoc.getLocWithOffset(1);
297 commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc));
298 return true;
299}
300
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000301void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
302 ObjCInterfaceDecl *D) {
303 for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
304 M != MEnd; ++M) {
305 ObjCMethodDecl *Method = (*M);
Fariborz Jahaniande661002013-07-03 23:44:11 +0000306 if (Method->isPropertyAccessor() || Method->param_size() != 0)
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000307 continue;
308 // Is this method candidate to be a getter?
Fariborz Jahaniande661002013-07-03 23:44:11 +0000309 QualType GRT = Method->getResultType();
310 if (GRT->isVoidType())
311 continue;
Fariborz Jahanian7ac20e12013-07-08 22:49:25 +0000312 // FIXME. Don't know what todo with attributes, skip for now.
313 if (Method->hasAttrs())
314 continue;
315
Fariborz Jahaniande661002013-07-03 23:44:11 +0000316 Selector GetterSelector = Method->getSelector();
317 IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
318 Selector SetterSelector =
319 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
320 PP.getSelectorTable(),
321 getterName);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000322 ObjCMethodDecl *SetterMethod = D->lookupMethod(SetterSelector, true);
323 bool GetterHasIsPrefix = false;
324 if (!SetterMethod) {
325 // try a different naming convention for getter: isXxxxx
326 StringRef getterNameString = getterName->getName();
Fariborz Jahanian261fdb72013-08-08 21:20:01 +0000327 if (getterNameString.startswith("is") && !GRT->isObjCRetainableType()) {
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000328 GetterHasIsPrefix = true;
329 const char *CGetterName = getterNameString.data() + 2;
Fariborz Jahanian261fdb72013-08-08 21:20:01 +0000330 if (CGetterName[0] && isUppercase(CGetterName[0])) {
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000331 getterName = &Ctx.Idents.get(CGetterName);
332 SetterSelector =
333 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
334 PP.getSelectorTable(),
335 getterName);
336 SetterMethod = D->lookupMethod(SetterSelector, true);
337 }
338 }
339 }
340 if (SetterMethod) {
Fariborz Jahaniande661002013-07-03 23:44:11 +0000341 // Is this a valid setter, matching the target getter?
342 QualType SRT = SetterMethod->getResultType();
343 if (!SRT->isVoidType())
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000344 continue;
Fariborz Jahaniande661002013-07-03 23:44:11 +0000345 const ParmVarDecl *argDecl = *SetterMethod->param_begin();
Fariborz Jahanian43bbaac2013-07-04 00:24:32 +0000346 QualType ArgType = argDecl->getType();
Fariborz Jahanian7ac20e12013-07-08 22:49:25 +0000347 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT) ||
348 SetterMethod->hasAttrs())
Fariborz Jahanian43bbaac2013-07-04 00:24:32 +0000349 continue;
Fariborz Jahanian266926d2013-07-05 20:46:03 +0000350 edit::Commit commit(*Editor);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000351 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
352 GetterHasIsPrefix);
Fariborz Jahanian266926d2013-07-05 20:46:03 +0000353 Editor->commit(commit);
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000354 }
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000355 }
356}
357
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000358static bool
Fariborz Jahanian9a3512b2013-07-13 17:16:41 +0000359ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000360 const ObjCImplementationDecl *ImpDecl,
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000361 const ObjCInterfaceDecl *IDecl,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000362 ObjCProtocolDecl *Protocol) {
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000363 // In auto-synthesis, protocol properties are not synthesized. So,
364 // a conforming protocol must have its required properties declared
365 // in class interface.
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000366 bool HasAtleastOneRequiredProperty = false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000367 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
368 for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
369 E = PDecl->prop_end(); P != E; ++P) {
370 ObjCPropertyDecl *Property = *P;
371 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
372 continue;
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000373 HasAtleastOneRequiredProperty = true;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000374 DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
Fariborz Jahanian2bc3dda2013-07-16 21:59:42 +0000375 if (R.size() == 0) {
376 // Relax the rule and look into class's implementation for a synthesize
377 // or dynamic declaration. Class is implementing a property coming from
378 // another protocol. This still makes the target protocol as conforming.
379 if (!ImpDecl->FindPropertyImplDecl(
380 Property->getDeclName().getAsIdentifierInfo()))
381 return false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000382 }
Fariborz Jahanian2bc3dda2013-07-16 21:59:42 +0000383 else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
384 if ((ClassProperty->getPropertyAttributes()
385 != Property->getPropertyAttributes()) ||
386 !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
387 return false;
388 }
389 else
390 return false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000391 }
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000392
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000393 // At this point, all required properties in this protocol conform to those
394 // declared in the class.
395 // Check that class implements the required methods of the protocol too.
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000396 bool HasAtleastOneRequiredMethod = false;
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000397 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
398 if (PDecl->meth_begin() == PDecl->meth_end())
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000399 return HasAtleastOneRequiredProperty;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000400 for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
401 MEnd = PDecl->meth_end(); M != MEnd; ++M) {
402 ObjCMethodDecl *MD = (*M);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000403 if (MD->isImplicit())
404 continue;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000405 if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
406 continue;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000407 DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000408 if (R.size() == 0)
409 return false;
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000410 bool match = false;
411 HasAtleastOneRequiredMethod = true;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000412 for (unsigned I = 0, N = R.size(); I != N; ++I)
413 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
414 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
415 match = true;
416 break;
417 }
418 if (!match)
419 return false;
420 }
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000421 }
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000422 if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
423 return true;
424 return false;
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000425}
426
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000427static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
428 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
429 const NSAPI &NS, edit::Commit &commit) {
430 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
431 std::string ClassString;
432 SourceLocation EndLoc =
433 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
434
435 if (Protocols.empty()) {
436 ClassString = '<';
437 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
438 ClassString += ConformingProtocols[i]->getNameAsString();
439 if (i != (e-1))
440 ClassString += ", ";
441 }
442 ClassString += "> ";
443 }
444 else {
445 ClassString = ", ";
446 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
447 ClassString += ConformingProtocols[i]->getNameAsString();
448 if (i != (e-1))
449 ClassString += ", ";
450 }
451 ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
452 EndLoc = *PL;
453 }
454
455 commit.insertAfterToken(EndLoc, ClassString);
456 return true;
457}
458
459static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
460 const TypedefDecl *TypedefDcl,
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000461 const NSAPI &NS, edit::Commit &commit,
462 bool IsNSIntegerType) {
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000463 std::string ClassString =
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000464 IsNSIntegerType ? "typedef NS_ENUM(NSInteger, " : "typedef NS_OPTIONS(NSUInteger, ";
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000465 ClassString += TypedefDcl->getIdentifier()->getName();
466 ClassString += ')';
467 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
468 commit.replace(R, ClassString);
469 SourceLocation EndOfTypedefLoc = TypedefDcl->getLocEnd();
470 EndOfTypedefLoc = trans::findLocationAfterSemi(EndOfTypedefLoc, NS.getASTContext());
471 if (!EndOfTypedefLoc.isInvalid()) {
472 commit.remove(SourceRange(TypedefDcl->getLocStart(), EndOfTypedefLoc));
473 return true;
474 }
475 return false;
476}
477
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000478static bool rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000479 const TypedefDecl *TypedefDcl,
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000480 const NSAPI &NS, edit::Commit &commit,
481 bool IsNSIntegerType) {
482 std::string ClassString =
483 IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000484 ClassString += TypedefDcl->getIdentifier()->getName();
485 ClassString += ')';
486 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
487 commit.replace(R, ClassString);
488 SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
489 commit.remove(SourceRange(TypedefLoc, TypedefLoc));
490 return true;
491}
492
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000493static bool UseNSOptionsMacro(ASTContext &Ctx,
494 const EnumDecl *EnumDcl) {
495 bool PowerOfTwo = true;
Fariborz Jahanianbe7bc112013-08-15 18:46:37 +0000496 uint64_t MaxPowerOfTwoVal = 0;
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000497 for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
498 EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
499 EnumConstantDecl *Enumerator = (*EI);
500 const Expr *InitExpr = Enumerator->getInitExpr();
501 if (!InitExpr) {
502 PowerOfTwo = false;
503 continue;
504 }
505 InitExpr = InitExpr->IgnoreImpCasts();
506 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
507 if (BO->isShiftOp() || BO->isBitwiseOp())
508 return true;
509
510 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
Fariborz Jahanianbe7bc112013-08-15 18:46:37 +0000511 if (PowerOfTwo && EnumVal) {
512 if (!llvm::isPowerOf2_64(EnumVal))
513 PowerOfTwo = false;
514 else if (EnumVal > MaxPowerOfTwoVal)
515 MaxPowerOfTwoVal = EnumVal;
516 }
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000517 }
Fariborz Jahanianbe7bc112013-08-15 18:46:37 +0000518 return PowerOfTwo ? ((MaxPowerOfTwoVal > 2) ? true : false) : false;
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000519}
520
Fariborz Jahanian008ef722013-07-19 17:44:32 +0000521void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000522 const ObjCImplementationDecl *ImpDecl) {
523 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
524 if (!IDecl || ObjCProtocolDecls.empty())
525 return;
526 // Find all implicit conforming protocols for this class
527 // and make them explicit.
528 llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
529 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000530 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000531
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000532 for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000533 ObjCProtocolDecls.begin(),
534 E = ObjCProtocolDecls.end(); I != E; ++I)
535 if (!ExplicitProtocols.count(*I))
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000536 PotentialImplicitProtocols.push_back(*I);
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000537
538 if (PotentialImplicitProtocols.empty())
539 return;
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000540
541 // go through list of non-optional methods and properties in each protocol
542 // in the PotentialImplicitProtocols list. If class implements every one of the
543 // methods and properties, then this class conforms to this protocol.
544 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
545 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000546 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000547 PotentialImplicitProtocols[i]))
548 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000549
550 if (ConformingProtocols.empty())
551 return;
Fariborz Jahaniancb7b8de2013-07-17 00:02:22 +0000552
553 // Further reduce number of conforming protocols. If protocol P1 is in the list
554 // protocol P2 (P2<P1>), No need to include P1.
555 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
556 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
557 bool DropIt = false;
558 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
559 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
560 ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
561 if (PDecl == TargetPDecl)
562 continue;
563 if (PDecl->lookupProtocolNamed(
564 TargetPDecl->getDeclName().getAsIdentifierInfo())) {
565 DropIt = true;
566 break;
567 }
568 }
569 if (!DropIt)
570 MinimalConformingProtocols.push_back(TargetPDecl);
571 }
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000572 edit::Commit commit(*Editor);
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000573 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
574 *NSAPIObj, commit);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000575 Editor->commit(commit);
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000576}
577
Fariborz Jahanian92463272013-07-18 20:11:45 +0000578void ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
579 const EnumDecl *EnumDcl,
580 const TypedefDecl *TypedefDcl) {
581 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
582 !TypedefDcl->getIdentifier())
583 return;
584
585 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000586 bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
587 bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000588
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000589 if (!IsNSIntegerType && !IsNSUIntegerType) {
590 // Also check for typedef enum {...} TD;
591 if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
592 if (EnumTy->getDecl() == EnumDcl) {
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000593 bool NSOptions = UseNSOptionsMacro(Ctx, EnumDcl);
594 if (NSOptions) {
595 if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
596 return;
597 }
598 else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000599 return;
600 edit::Commit commit(*Editor);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000601 rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000602 Editor->commit(commit);
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000603 }
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000604 }
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000605 return;
606 }
607 if (IsNSIntegerType && UseNSOptionsMacro(Ctx, EnumDcl)) {
608 // We may still use NS_OPTIONS based on what we find in the enumertor list.
609 IsNSIntegerType = false;
610 IsNSUIntegerType = true;
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000611 }
Fariborz Jahanian92463272013-07-18 20:11:45 +0000612
613 // NS_ENUM must be available.
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000614 if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
615 return;
616 // NS_OPTIONS must be available.
617 if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
Fariborz Jahanian92463272013-07-18 20:11:45 +0000618 return;
619 edit::Commit commit(*Editor);
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000620 rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, IsNSIntegerType);
Fariborz Jahanian92463272013-07-18 20:11:45 +0000621 Editor->commit(commit);
622}
623
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000624static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
625 ObjCMethodDecl *OM) {
626 SourceRange R;
627 std::string ClassString;
628 if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
629 TypeLoc TL = TSInfo->getTypeLoc();
630 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
631 ClassString = "instancetype";
632 }
633 else {
634 R = SourceRange(OM->getLocStart(), OM->getLocStart());
635 ClassString = OM->isInstanceMethod() ? '-' : '+';
636 ClassString += " (instancetype)";
637 }
638 edit::Commit commit(*ASTC.Editor);
639 commit.replace(R, ClassString);
640 ASTC.Editor->commit(commit);
641}
642
Fariborz Jahanian670ef262013-07-23 23:34:42 +0000643void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
644 ObjCContainerDecl *CDecl,
645 ObjCMethodDecl *OM) {
Fariborz Jahanian71221352013-07-23 22:42:28 +0000646 ObjCInstanceTypeFamily OIT_Family =
647 Selector::getInstTypeMethodFamily(OM->getSelector());
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000648
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000649 std::string ClassName;
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000650 switch (OIT_Family) {
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000651 case OIT_None:
652 migrateFactoryMethod(Ctx, CDecl, OM);
653 return;
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000654 case OIT_Array:
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000655 ClassName = "NSArray";
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000656 break;
657 case OIT_Dictionary:
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000658 ClassName = "NSDictionary";
659 break;
660 case OIT_MemManage:
661 ClassName = "NSObject";
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000662 break;
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000663 case OIT_Singleton:
664 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000665 return;
666 }
Fariborz Jahanian71221352013-07-23 22:42:28 +0000667 if (!OM->getResultType()->isObjCIdType())
668 return;
669
670 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
671 if (!IDecl) {
672 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
673 IDecl = CatDecl->getClassInterface();
674 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
675 IDecl = ImpDecl->getClassInterface();
676 }
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000677 if (!IDecl ||
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000678 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
679 migrateFactoryMethod(Ctx, CDecl, OM);
Fariborz Jahanian71221352013-07-23 22:42:28 +0000680 return;
Fariborz Jahanian280954a2013-07-24 18:31:42 +0000681 }
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000682 ReplaceWithInstancetype(*this, OM);
Fariborz Jahanian71221352013-07-23 22:42:28 +0000683}
684
685void ObjCMigrateASTConsumer::migrateInstanceType(ASTContext &Ctx,
686 ObjCContainerDecl *CDecl) {
687 // migrate methods which can have instancetype as their result type.
688 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
689 MEnd = CDecl->meth_end();
690 M != MEnd; ++M) {
691 ObjCMethodDecl *Method = (*M);
692 migrateMethodInstanceType(Ctx, CDecl, Method);
693 }
694}
695
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000696void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
697 ObjCContainerDecl *CDecl,
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000698 ObjCMethodDecl *OM,
699 ObjCInstanceTypeFamily OIT_Family) {
Fariborz Jahanian3bfc35e2013-08-02 22:34:18 +0000700 if (OM->isInstanceMethod() ||
701 OM->getResultType() == Ctx.getObjCInstanceType() ||
702 !OM->getResultType()->isObjCIdType())
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000703 return;
704
705 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
706 // NSYYYNamE with matching names be at least 3 characters long.
707 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
708 if (!IDecl) {
709 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
710 IDecl = CatDecl->getClassInterface();
711 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
712 IDecl = ImpDecl->getClassInterface();
713 }
714 if (!IDecl)
715 return;
716
717 std::string StringClassName = IDecl->getName();
718 StringRef LoweredClassName(StringClassName);
719 std::string StringLoweredClassName = LoweredClassName.lower();
720 LoweredClassName = StringLoweredClassName;
721
722 IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +0000723 // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
724 if (!MethodIdName)
725 return;
726
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000727 std::string MethodName = MethodIdName->getName();
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000728 if (OIT_Family == OIT_Singleton) {
729 StringRef STRefMethodName(MethodName);
730 size_t len = 0;
731 if (STRefMethodName.startswith("standard"))
732 len = strlen("standard");
733 else if (STRefMethodName.startswith("shared"))
734 len = strlen("shared");
735 else if (STRefMethodName.startswith("default"))
736 len = strlen("default");
737 else
738 return;
739 MethodName = STRefMethodName.substr(len);
740 }
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000741 std::string MethodNameSubStr = MethodName.substr(0, 3);
742 StringRef MethodNamePrefix(MethodNameSubStr);
743 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
744 MethodNamePrefix = StringLoweredMethodNamePrefix;
745 size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
746 if (Ix == StringRef::npos)
747 return;
748 std::string ClassNamePostfix = LoweredClassName.substr(Ix);
749 StringRef LoweredMethodName(MethodName);
750 std::string StringLoweredMethodName = LoweredMethodName.lower();
751 LoweredMethodName = StringLoweredMethodName;
752 if (!LoweredMethodName.startswith(ClassNamePostfix))
753 return;
754 ReplaceWithInstancetype(*this, OM);
755}
756
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +0000757void ObjCMigrateASTConsumer::migrateFunctionDeclAnnotation(
758 ASTContext &Ctx,
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +0000759 const FunctionDecl *FuncDecl) {
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +0000760 if (FuncDecl->hasAttr<CFAuditedTransferAttr>() ||
761 FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +0000762 FuncDecl->getAttr<CFReturnsNotRetainedAttr>() ||
763 FuncDecl->hasBody())
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +0000764 return;
765}
766
767void ObjCMigrateASTConsumer::migrateObjCMethodDeclAnnotation(
768 ASTContext &Ctx,
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +0000769 const ObjCMethodDecl *MethodDecl) {
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +0000770 if (MethodDecl->hasAttr<CFAuditedTransferAttr>() ||
771 MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +0000772 MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
773 MethodDecl->hasBody())
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +0000774 return;
775}
776
Ted Kremenekf7639e12012-03-06 20:06:33 +0000777namespace {
778
779class RewritesReceiver : public edit::EditsReceiver {
780 Rewriter &Rewrite;
781
782public:
783 RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
784
785 virtual void insert(SourceLocation loc, StringRef text) {
786 Rewrite.InsertText(loc, text);
787 }
788 virtual void replace(CharSourceRange range, StringRef text) {
789 Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
790 }
791};
792
793}
794
795void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000796
797 TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000798 if (MigrateProperty)
799 for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
800 D != DEnd; ++D) {
801 if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
802 migrateObjCInterfaceDecl(Ctx, CDecl);
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000803 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
804 ObjCProtocolDecls.insert(PDecl);
805 else if (const ObjCImplementationDecl *ImpDecl =
806 dyn_cast<ObjCImplementationDecl>(*D))
807 migrateProtocolConformance(Ctx, ImpDecl);
Fariborz Jahanian92463272013-07-18 20:11:45 +0000808 else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
809 DeclContext::decl_iterator N = D;
810 ++N;
Fariborz Jahanian008ef722013-07-19 17:44:32 +0000811 if (N != DEnd)
812 if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N))
813 migrateNSEnumDecl(Ctx, ED, TD);
Fariborz Jahanian92463272013-07-18 20:11:45 +0000814 }
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +0000815 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D))
816 migrateFunctionDeclAnnotation(Ctx, FD);
817 else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*D))
818 migrateObjCMethodDeclAnnotation(Ctx, MD);
819
Fariborz Jahanian71221352013-07-23 22:42:28 +0000820 // migrate methods which can have instancetype as their result type.
821 if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D))
822 migrateInstanceType(Ctx, CDecl);
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000823 }
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000824
David Blaikiebbafb8a2012-03-11 07:00:24 +0000825 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
Ted Kremenekf7639e12012-03-06 20:06:33 +0000826 RewritesReceiver Rec(rewriter);
827 Editor->applyRewrites(Rec);
828
829 for (Rewriter::buffer_iterator
830 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
831 FileID FID = I->first;
832 RewriteBuffer &buf = I->second;
833 const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
834 assert(file);
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000835 SmallString<512> newText;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000836 llvm::raw_svector_ostream vecOS(newText);
837 buf.write(vecOS);
838 vecOS.flush();
839 llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
840 StringRef(newText.data(), newText.size()), file->getName());
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000841 SmallString<64> filePath(file->getName());
Ted Kremenekf7639e12012-03-06 20:06:33 +0000842 FileMgr.FixupRelativePath(filePath);
843 Remapper.remap(filePath.str(), memBuf);
844 }
845
846 if (IsOutputFile) {
847 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
848 } else {
849 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
850 }
851}
852
853bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
Argyrios Kyrtzidisb4822602012-05-24 16:48:23 +0000854 CI.getDiagnostics().setIgnoreAllWarnings(true);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000855 return true;
856}
857
858ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
859 StringRef InFile) {
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +0000860 PPConditionalDirectiveRecord *
861 PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
862 CI.getPreprocessor().addPPCallbacks(PPRec);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000863 return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
864 /*MigrateLiterals=*/true,
865 /*MigrateSubscripting=*/true,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000866 /*MigrateProperty*/true,
Ted Kremenekf7639e12012-03-06 20:06:33 +0000867 Remapper,
868 CI.getFileManager(),
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +0000869 PPRec,
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000870 CI.getPreprocessor(),
Ted Kremenekf7639e12012-03-06 20:06:33 +0000871 /*isOutputFile=*/true);
872}