blob: 86312b6e0c0ff023ebdc238fed790e9348d6f90d [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 Jahanian9ef4a262013-08-19 19:13:34 +000027#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
Fariborz Jahanian84ac1de2013-08-15 21:44:38 +000028#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000029#include "clang/AST/Attr.h"
Ted Kremenekf7639e12012-03-06 20:06:33 +000030#include "llvm/ADT/SmallString.h"
31
32using namespace clang;
33using namespace arcmt;
Fariborz Jahanian84ac1de2013-08-15 21:44:38 +000034using namespace ento::objc_retain;
Ted Kremenekf7639e12012-03-06 20:06:33 +000035
36namespace {
37
38class ObjCMigrateASTConsumer : public ASTConsumer {
Fariborz Jahanian63ffce22013-08-27 22:42:30 +000039 enum CF_BRIDGING_KIND {
40 CF_BRIDGING_NONE,
41 CF_BRIDGING_ENABLE,
42 CF_BRIDGING_MAY_INCLUDE
43 };
44
Ted Kremenekf7639e12012-03-06 20:06:33 +000045 void migrateDecl(Decl *D);
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000046 void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCInterfaceDecl *D);
Fariborz Jahanian1be01532013-07-12 22:32:19 +000047 void migrateProtocolConformance(ASTContext &Ctx,
48 const ObjCImplementationDecl *ImpDecl);
Fariborz Jahanian92463272013-07-18 20:11:45 +000049 void migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
50 const TypedefDecl *TypedefDcl);
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +000051 void migrateMethods(ASTContext &Ctx, ObjCContainerDecl *CDecl);
Fariborz Jahanian670ef262013-07-23 23:34:42 +000052 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
53 ObjCMethodDecl *OM);
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +000054 void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
Fariborz Jahanianc4291852013-08-02 18:00:53 +000055 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
Fariborz Jahanian9275c682013-08-02 20:54:18 +000056 ObjCMethodDecl *OM,
57 ObjCInstanceTypeFamily OIT_Family = OIT_None);
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000058
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +000059 void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +000060 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +000061 const FunctionDecl *FuncDecl, bool ResultAnnotated);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +000062 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +000063 const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +000064
Fariborz Jahanian301b5212013-08-20 22:42:13 +000065 void AnnotateImplicitBridging(ASTContext &Ctx);
66
Fariborz Jahanian63ffce22013-08-27 22:42:30 +000067 CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
68 const FunctionDecl *FuncDecl);
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000069
Fariborz Jahanian926fafb2013-08-22 18:35:27 +000070 void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
71
Fariborz Jahanian89f6d102013-09-04 00:10:06 +000072 void migrateAddMethodAnnotation(ASTContext &Ctx,
73 const ObjCMethodDecl *MethodDecl);
Ted Kremenekf7639e12012-03-06 20:06:33 +000074public:
75 std::string MigrateDir;
76 bool MigrateLiterals;
77 bool MigrateSubscripting;
Fariborz Jahaniand83ef842013-07-09 16:59:14 +000078 bool MigrateProperty;
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +000079 bool MigrateReadonlyProperty;
Fariborz Jahanianb8343522013-08-20 23:35:26 +000080 unsigned FileId;
Dmitri Gribenkof8579502013-01-12 19:30:44 +000081 OwningPtr<NSAPI> NSAPIObj;
82 OwningPtr<edit::EditedSource> Editor;
Ted Kremenekf7639e12012-03-06 20:06:33 +000083 FileRemapper &Remapper;
84 FileManager &FileMgr;
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +000085 const PPConditionalDirectiveRecord *PPRec;
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000086 Preprocessor &PP;
Ted Kremenekf7639e12012-03-06 20:06:33 +000087 bool IsOutputFile;
Fariborz Jahanian1be01532013-07-12 22:32:19 +000088 llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
Fariborz Jahanian926fafb2013-08-22 18:35:27 +000089 llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
Fariborz Jahanian1be01532013-07-12 22:32:19 +000090
Ted Kremenekf7639e12012-03-06 20:06:33 +000091 ObjCMigrateASTConsumer(StringRef migrateDir,
92 bool migrateLiterals,
93 bool migrateSubscripting,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +000094 bool migrateProperty,
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +000095 bool migrateReadonlyProperty,
Ted Kremenekf7639e12012-03-06 20:06:33 +000096 FileRemapper &remapper,
97 FileManager &fileMgr,
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +000098 const PPConditionalDirectiveRecord *PPRec,
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000099 Preprocessor &PP,
Ted Kremenekf7639e12012-03-06 20:06:33 +0000100 bool isOutputFile = false)
101 : MigrateDir(migrateDir),
102 MigrateLiterals(migrateLiterals),
103 MigrateSubscripting(migrateSubscripting),
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000104 MigrateProperty(migrateProperty),
105 MigrateReadonlyProperty(migrateReadonlyProperty),
106 FileId(0), Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
Ted Kremenekf7639e12012-03-06 20:06:33 +0000107 IsOutputFile(isOutputFile) { }
108
109protected:
110 virtual void Initialize(ASTContext &Context) {
111 NSAPIObj.reset(new NSAPI(Context));
112 Editor.reset(new edit::EditedSource(Context.getSourceManager(),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000113 Context.getLangOpts(),
Ted Kremenekf7639e12012-03-06 20:06:33 +0000114 PPRec));
115 }
116
117 virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
118 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
119 migrateDecl(*I);
120 return true;
121 }
122 virtual void HandleInterestingDecl(DeclGroupRef DG) {
123 // Ignore decls from the PCH.
124 }
125 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
126 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
127 }
128
129 virtual void HandleTranslationUnit(ASTContext &Ctx);
130};
131
132}
133
134ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
135 StringRef migrateDir,
136 bool migrateLiterals,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000137 bool migrateSubscripting,
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000138 bool migrateProperty,
139 bool migrateReadonlyProperty)
Ted Kremenekf7639e12012-03-06 20:06:33 +0000140 : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
141 MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000142 MigrateProperty(migrateProperty),
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000143 MigrateReadonlyProperty(migrateReadonlyProperty),
Ted Kremenekf7639e12012-03-06 20:06:33 +0000144 CompInst(0) {
145 if (MigrateDir.empty())
146 MigrateDir = "."; // user current directory if none is given.
147}
148
149ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
150 StringRef InFile) {
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +0000151 PPConditionalDirectiveRecord *
152 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
153 CompInst->getPreprocessor().addPPCallbacks(PPRec);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000154 ASTConsumer *
155 WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
156 ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
157 MigrateLiterals,
158 MigrateSubscripting,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +0000159 MigrateProperty,
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000160 MigrateReadonlyProperty,
Ted Kremenekf7639e12012-03-06 20:06:33 +0000161 Remapper,
162 CompInst->getFileManager(),
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000163 PPRec,
164 CompInst->getPreprocessor());
Ted Kremenekf7639e12012-03-06 20:06:33 +0000165 ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
166 return new MultiplexConsumer(Consumers);
167}
168
169bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
170 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
171 /*ignoreIfFilesChanges=*/true);
172 CompInst = &CI;
173 CI.getDiagnostics().setIgnoreAllWarnings(true);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000174 return true;
175}
176
177namespace {
178class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
179 ObjCMigrateASTConsumer &Consumer;
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000180 ParentMap &PMap;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000181
182public:
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000183 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
184 : Consumer(consumer), PMap(PMap) { }
Ted Kremenekf7639e12012-03-06 20:06:33 +0000185
186 bool shouldVisitTemplateInstantiations() const { return false; }
187 bool shouldWalkTypesOfTypeLocs() const { return false; }
188
189 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
190 if (Consumer.MigrateLiterals) {
191 edit::Commit commit(*Consumer.Editor);
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000192 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000193 Consumer.Editor->commit(commit);
194 }
195
196 if (Consumer.MigrateSubscripting) {
197 edit::Commit commit(*Consumer.Editor);
198 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
199 Consumer.Editor->commit(commit);
200 }
201
202 return true;
203 }
204
205 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
206 // Do depth first; we want to rewrite the subexpressions first so that if
207 // we have to move expressions we will move them already rewritten.
208 for (Stmt::child_range range = E->children(); range; ++range)
209 if (!TraverseStmt(*range))
210 return false;
211
212 return WalkUpFromObjCMessageExpr(E);
213 }
214};
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000215
216class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
217 ObjCMigrateASTConsumer &Consumer;
218 OwningPtr<ParentMap> PMap;
219
220public:
221 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
222
223 bool shouldVisitTemplateInstantiations() const { return false; }
224 bool shouldWalkTypesOfTypeLocs() const { return false; }
225
226 bool TraverseStmt(Stmt *S) {
227 PMap.reset(new ParentMap(S));
228 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
229 return true;
230 }
231};
Ted Kremenekf7639e12012-03-06 20:06:33 +0000232}
233
234void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
235 if (!D)
236 return;
237 if (isa<ObjCMethodDecl>(D))
238 return; // Wait for the ObjC container declaration.
239
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000240 BodyMigrator(*this).TraverseDecl(D);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000241}
242
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000243static void append_attr(std::string &PropertyString, const char *attr) {
244 PropertyString += ", ";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000245 PropertyString += attr;
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000246}
247
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000248static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter,
249 const ObjCMethodDecl *Setter,
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000250 const NSAPI &NS, edit::Commit &commit,
251 bool GetterHasIsPrefix) {
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000252 ASTContext &Context = NS.getASTContext();
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000253 std::string PropertyString = "@property(nonatomic";
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000254 std::string PropertyNameString = Getter->getNameAsString();
255 StringRef PropertyName(PropertyNameString);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000256 if (GetterHasIsPrefix) {
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000257 PropertyString += ", getter=";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000258 PropertyString += PropertyNameString;
259 }
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000260 // Property with no setter may be suggested as a 'readonly' property.
261 if (!Setter)
262 append_attr(PropertyString, "readonly");
263
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000264 // Short circuit properties that contain the name "delegate" or "dataSource",
265 // or have exact name "target" to have unsafe_unretained attribute.
266 if (PropertyName.equals("target") ||
267 (PropertyName.find("delegate") != StringRef::npos) ||
268 (PropertyName.find("dataSource") != StringRef::npos))
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000269 append_attr(PropertyString, "unsafe_unretained");
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000270 else if (Setter) {
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000271 const ParmVarDecl *argDecl = *Setter->param_begin();
272 QualType ArgType = Context.getCanonicalType(argDecl->getType());
273 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
274 bool RetainableObject = ArgType->isObjCRetainableType();
275 if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
276 if (const ObjCObjectPointerType *ObjPtrTy =
277 ArgType->getAs<ObjCObjectPointerType>()) {
278 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
279 if (IDecl &&
280 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000281 append_attr(PropertyString, "copy");
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000282 else
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000283 append_attr(PropertyString, "retain");
284 }
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000285 } else if (propertyLifetime == Qualifiers::OCL_Weak)
286 // TODO. More precise determination of 'weak' attribute requires
287 // looking into setter's implementation for backing weak ivar.
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000288 append_attr(PropertyString, "weak");
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000289 else if (RetainableObject)
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000290 append_attr(PropertyString, "retain");
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000291 }
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000292 PropertyString += ')';
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000293
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000294 QualType RT = Getter->getResultType();
295 if (!isa<TypedefType>(RT)) {
296 // strip off any ARC lifetime qualifier.
297 QualType CanResultTy = Context.getCanonicalType(RT);
298 if (CanResultTy.getQualifiers().hasObjCLifetime()) {
299 Qualifiers Qs = CanResultTy.getQualifiers();
300 Qs.removeObjCLifetime();
301 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
302 }
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000303 }
304 PropertyString += " ";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000305 PropertyString += RT.getAsString(Context.getPrintingPolicy());
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000306 PropertyString += " ";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000307 if (GetterHasIsPrefix) {
308 // property name must strip off "is" and lower case the first character
309 // after that; e.g. isContinuous will become continuous.
310 StringRef PropertyNameStringRef(PropertyNameString);
311 PropertyNameStringRef = PropertyNameStringRef.drop_front(2);
312 PropertyNameString = PropertyNameStringRef;
313 std::string NewPropertyNameString = PropertyNameString;
Fariborz Jahaniandb8bf832013-08-08 21:51:06 +0000314 NewPropertyNameString[0] = toLowercase(NewPropertyNameString[0]);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000315 PropertyString += NewPropertyNameString;
316 }
317 else
318 PropertyString += PropertyNameString;
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000319 commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
320 Getter->getDeclaratorEndLoc()),
321 PropertyString);
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000322 if (Setter) {
323 SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
324 // Get location past ';'
325 EndLoc = EndLoc.getLocWithOffset(1);
326 commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc));
327 }
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000328 return true;
329}
330
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000331void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
332 ObjCInterfaceDecl *D) {
333 for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
334 M != MEnd; ++M) {
335 ObjCMethodDecl *Method = (*M);
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000336 if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
337 Method->param_size() != 0)
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000338 continue;
339 // Is this method candidate to be a getter?
Fariborz Jahaniande661002013-07-03 23:44:11 +0000340 QualType GRT = Method->getResultType();
341 if (GRT->isVoidType())
342 continue;
Fariborz Jahanian7ac20e12013-07-08 22:49:25 +0000343 // FIXME. Don't know what todo with attributes, skip for now.
344 if (Method->hasAttrs())
345 continue;
346
Fariborz Jahaniande661002013-07-03 23:44:11 +0000347 Selector GetterSelector = Method->getSelector();
348 IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
349 Selector SetterSelector =
350 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
351 PP.getSelectorTable(),
352 getterName);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000353 ObjCMethodDecl *SetterMethod = D->lookupMethod(SetterSelector, true);
354 bool GetterHasIsPrefix = false;
355 if (!SetterMethod) {
356 // try a different naming convention for getter: isXxxxx
357 StringRef getterNameString = getterName->getName();
Fariborz Jahanian261fdb72013-08-08 21:20:01 +0000358 if (getterNameString.startswith("is") && !GRT->isObjCRetainableType()) {
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000359 GetterHasIsPrefix = true;
360 const char *CGetterName = getterNameString.data() + 2;
Fariborz Jahanian261fdb72013-08-08 21:20:01 +0000361 if (CGetterName[0] && isUppercase(CGetterName[0])) {
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000362 getterName = &Ctx.Idents.get(CGetterName);
363 SetterSelector =
364 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
365 PP.getSelectorTable(),
366 getterName);
367 SetterMethod = D->lookupMethod(SetterSelector, true);
368 }
369 }
370 }
371 if (SetterMethod) {
Fariborz Jahaniande661002013-07-03 23:44:11 +0000372 // Is this a valid setter, matching the target getter?
373 QualType SRT = SetterMethod->getResultType();
374 if (!SRT->isVoidType())
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000375 continue;
Fariborz Jahaniande661002013-07-03 23:44:11 +0000376 const ParmVarDecl *argDecl = *SetterMethod->param_begin();
Fariborz Jahanian43bbaac2013-07-04 00:24:32 +0000377 QualType ArgType = argDecl->getType();
Fariborz Jahanian7ac20e12013-07-08 22:49:25 +0000378 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT) ||
379 SetterMethod->hasAttrs())
Fariborz Jahanian43bbaac2013-07-04 00:24:32 +0000380 continue;
Fariborz Jahanian266926d2013-07-05 20:46:03 +0000381 edit::Commit commit(*Editor);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000382 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
383 GetterHasIsPrefix);
Fariborz Jahanian266926d2013-07-05 20:46:03 +0000384 Editor->commit(commit);
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000385 }
386 else if (MigrateReadonlyProperty) {
387 // Try a non-void method with no argument (and no setter or property of same name
388 // as a 'readonly' property.
389 edit::Commit commit(*Editor);
390 rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
391 false /*GetterHasIsPrefix*/);
392 Editor->commit(commit);
393 }
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000394 }
395}
396
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000397static bool
Fariborz Jahanian9a3512b2013-07-13 17:16:41 +0000398ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000399 const ObjCImplementationDecl *ImpDecl,
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000400 const ObjCInterfaceDecl *IDecl,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000401 ObjCProtocolDecl *Protocol) {
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000402 // In auto-synthesis, protocol properties are not synthesized. So,
403 // a conforming protocol must have its required properties declared
404 // in class interface.
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000405 bool HasAtleastOneRequiredProperty = false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000406 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
407 for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
408 E = PDecl->prop_end(); P != E; ++P) {
409 ObjCPropertyDecl *Property = *P;
410 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
411 continue;
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000412 HasAtleastOneRequiredProperty = true;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000413 DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
Fariborz Jahanian2bc3dda2013-07-16 21:59:42 +0000414 if (R.size() == 0) {
415 // Relax the rule and look into class's implementation for a synthesize
416 // or dynamic declaration. Class is implementing a property coming from
417 // another protocol. This still makes the target protocol as conforming.
418 if (!ImpDecl->FindPropertyImplDecl(
419 Property->getDeclName().getAsIdentifierInfo()))
420 return false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000421 }
Fariborz Jahanian2bc3dda2013-07-16 21:59:42 +0000422 else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
423 if ((ClassProperty->getPropertyAttributes()
424 != Property->getPropertyAttributes()) ||
425 !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
426 return false;
427 }
428 else
429 return false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000430 }
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000431
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000432 // At this point, all required properties in this protocol conform to those
433 // declared in the class.
434 // Check that class implements the required methods of the protocol too.
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000435 bool HasAtleastOneRequiredMethod = false;
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000436 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
437 if (PDecl->meth_begin() == PDecl->meth_end())
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000438 return HasAtleastOneRequiredProperty;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000439 for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
440 MEnd = PDecl->meth_end(); M != MEnd; ++M) {
441 ObjCMethodDecl *MD = (*M);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000442 if (MD->isImplicit())
443 continue;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000444 if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
445 continue;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000446 DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000447 if (R.size() == 0)
448 return false;
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000449 bool match = false;
450 HasAtleastOneRequiredMethod = true;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000451 for (unsigned I = 0, N = R.size(); I != N; ++I)
452 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
453 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
454 match = true;
455 break;
456 }
457 if (!match)
458 return false;
459 }
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000460 }
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000461 if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
462 return true;
463 return false;
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000464}
465
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000466static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
467 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
468 const NSAPI &NS, edit::Commit &commit) {
469 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
470 std::string ClassString;
471 SourceLocation EndLoc =
472 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
473
474 if (Protocols.empty()) {
475 ClassString = '<';
476 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
477 ClassString += ConformingProtocols[i]->getNameAsString();
478 if (i != (e-1))
479 ClassString += ", ";
480 }
481 ClassString += "> ";
482 }
483 else {
484 ClassString = ", ";
485 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
486 ClassString += ConformingProtocols[i]->getNameAsString();
487 if (i != (e-1))
488 ClassString += ", ";
489 }
490 ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
491 EndLoc = *PL;
492 }
493
494 commit.insertAfterToken(EndLoc, ClassString);
495 return true;
496}
497
498static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
499 const TypedefDecl *TypedefDcl,
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000500 const NSAPI &NS, edit::Commit &commit,
Fariborz Jahanianff3476e2013-08-30 17:46:01 +0000501 bool IsNSIntegerType,
502 bool NSOptions) {
503 std::string ClassString;
504 if (NSOptions)
505 ClassString = "typedef NS_OPTIONS(NSUInteger, ";
506 else
507 ClassString =
508 IsNSIntegerType ? "typedef NS_ENUM(NSInteger, "
509 : "typedef NS_ENUM(NSUInteger, ";
510
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000511 ClassString += TypedefDcl->getIdentifier()->getName();
512 ClassString += ')';
513 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
514 commit.replace(R, ClassString);
515 SourceLocation EndOfTypedefLoc = TypedefDcl->getLocEnd();
516 EndOfTypedefLoc = trans::findLocationAfterSemi(EndOfTypedefLoc, NS.getASTContext());
517 if (!EndOfTypedefLoc.isInvalid()) {
518 commit.remove(SourceRange(TypedefDcl->getLocStart(), EndOfTypedefLoc));
519 return true;
520 }
521 return false;
522}
523
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000524static bool rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000525 const TypedefDecl *TypedefDcl,
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000526 const NSAPI &NS, edit::Commit &commit,
527 bool IsNSIntegerType) {
528 std::string ClassString =
529 IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000530 ClassString += TypedefDcl->getIdentifier()->getName();
531 ClassString += ')';
532 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
533 commit.replace(R, ClassString);
534 SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
535 commit.remove(SourceRange(TypedefLoc, TypedefLoc));
536 return true;
537}
538
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000539static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000540 const EnumDecl *EnumDcl) {
541 bool PowerOfTwo = true;
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000542 bool FoundHexdecimalEnumerator = false;
Fariborz Jahanianbe7bc112013-08-15 18:46:37 +0000543 uint64_t MaxPowerOfTwoVal = 0;
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000544 for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
545 EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
546 EnumConstantDecl *Enumerator = (*EI);
547 const Expr *InitExpr = Enumerator->getInitExpr();
548 if (!InitExpr) {
549 PowerOfTwo = false;
550 continue;
551 }
552 InitExpr = InitExpr->IgnoreImpCasts();
553 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
554 if (BO->isShiftOp() || BO->isBitwiseOp())
555 return true;
556
557 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
Fariborz Jahanianbe7bc112013-08-15 18:46:37 +0000558 if (PowerOfTwo && EnumVal) {
559 if (!llvm::isPowerOf2_64(EnumVal))
560 PowerOfTwo = false;
561 else if (EnumVal > MaxPowerOfTwoVal)
562 MaxPowerOfTwoVal = EnumVal;
563 }
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000564 if (!FoundHexdecimalEnumerator) {
565 SourceLocation EndLoc = Enumerator->getLocEnd();
566 Token Tok;
567 if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
568 if (Tok.isLiteral() && Tok.getLength() > 2) {
569 if (const char *StringLit = Tok.getLiteralData())
570 FoundHexdecimalEnumerator =
571 (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
572 }
573 }
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000574 }
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000575 return FoundHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000576}
577
Fariborz Jahanian008ef722013-07-19 17:44:32 +0000578void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000579 const ObjCImplementationDecl *ImpDecl) {
580 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
581 if (!IDecl || ObjCProtocolDecls.empty())
582 return;
583 // Find all implicit conforming protocols for this class
584 // and make them explicit.
585 llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
586 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000587 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000588
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000589 for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000590 ObjCProtocolDecls.begin(),
591 E = ObjCProtocolDecls.end(); I != E; ++I)
592 if (!ExplicitProtocols.count(*I))
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000593 PotentialImplicitProtocols.push_back(*I);
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000594
595 if (PotentialImplicitProtocols.empty())
596 return;
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000597
598 // go through list of non-optional methods and properties in each protocol
599 // in the PotentialImplicitProtocols list. If class implements every one of the
600 // methods and properties, then this class conforms to this protocol.
601 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
602 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000603 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000604 PotentialImplicitProtocols[i]))
605 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000606
607 if (ConformingProtocols.empty())
608 return;
Fariborz Jahaniancb7b8de2013-07-17 00:02:22 +0000609
610 // Further reduce number of conforming protocols. If protocol P1 is in the list
611 // protocol P2 (P2<P1>), No need to include P1.
612 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
613 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
614 bool DropIt = false;
615 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
616 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
617 ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
618 if (PDecl == TargetPDecl)
619 continue;
620 if (PDecl->lookupProtocolNamed(
621 TargetPDecl->getDeclName().getAsIdentifierInfo())) {
622 DropIt = true;
623 break;
624 }
625 }
626 if (!DropIt)
627 MinimalConformingProtocols.push_back(TargetPDecl);
628 }
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000629 edit::Commit commit(*Editor);
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000630 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
631 *NSAPIObj, commit);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000632 Editor->commit(commit);
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000633}
634
Fariborz Jahanian92463272013-07-18 20:11:45 +0000635void ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
636 const EnumDecl *EnumDcl,
637 const TypedefDecl *TypedefDcl) {
638 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
639 !TypedefDcl->getIdentifier())
640 return;
641
642 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000643 bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
644 bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000645
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000646 if (!IsNSIntegerType && !IsNSUIntegerType) {
647 // Also check for typedef enum {...} TD;
648 if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
649 if (EnumTy->getDecl() == EnumDcl) {
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000650 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000651 if (NSOptions) {
652 if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
653 return;
654 }
655 else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000656 return;
657 edit::Commit commit(*Editor);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000658 rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000659 Editor->commit(commit);
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000660 }
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000661 }
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000662 return;
663 }
Fariborz Jahanian92463272013-07-18 20:11:45 +0000664
Fariborz Jahanianff3476e2013-08-30 17:46:01 +0000665 // We may still use NS_OPTIONS based on what we find in the enumertor list.
666 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
Fariborz Jahanian92463272013-07-18 20:11:45 +0000667 // NS_ENUM must be available.
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000668 if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
669 return;
670 // NS_OPTIONS must be available.
671 if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
Fariborz Jahanian92463272013-07-18 20:11:45 +0000672 return;
673 edit::Commit commit(*Editor);
Fariborz Jahanianff3476e2013-08-30 17:46:01 +0000674 rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, IsNSIntegerType, NSOptions);
Fariborz Jahanian92463272013-07-18 20:11:45 +0000675 Editor->commit(commit);
676}
677
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000678static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
679 ObjCMethodDecl *OM) {
680 SourceRange R;
681 std::string ClassString;
682 if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
683 TypeLoc TL = TSInfo->getTypeLoc();
684 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
685 ClassString = "instancetype";
686 }
687 else {
688 R = SourceRange(OM->getLocStart(), OM->getLocStart());
689 ClassString = OM->isInstanceMethod() ? '-' : '+';
690 ClassString += " (instancetype)";
691 }
692 edit::Commit commit(*ASTC.Editor);
693 commit.replace(R, ClassString);
694 ASTC.Editor->commit(commit);
695}
696
Fariborz Jahanian670ef262013-07-23 23:34:42 +0000697void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
698 ObjCContainerDecl *CDecl,
699 ObjCMethodDecl *OM) {
Fariborz Jahanian7dd71432013-08-28 21:23:00 +0000700 // bail out early and do not suggest 'instancetype' when the method already
701 // has a related result type,
702 if (OM->hasRelatedResultType())
703 return;
704
Fariborz Jahanian71221352013-07-23 22:42:28 +0000705 ObjCInstanceTypeFamily OIT_Family =
706 Selector::getInstTypeMethodFamily(OM->getSelector());
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000707
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000708 std::string ClassName;
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000709 switch (OIT_Family) {
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000710 case OIT_None:
711 migrateFactoryMethod(Ctx, CDecl, OM);
712 return;
Fariborz Jahanian7dd71432013-08-28 21:23:00 +0000713 case OIT_Array:
714 ClassName = "NSArray";
715 break;
716 case OIT_Dictionary:
717 ClassName = "NSDictionary";
718 break;
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000719 case OIT_Singleton:
720 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000721 return;
722 }
Fariborz Jahanian71221352013-07-23 22:42:28 +0000723 if (!OM->getResultType()->isObjCIdType())
724 return;
725
726 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
727 if (!IDecl) {
728 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
729 IDecl = CatDecl->getClassInterface();
730 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
731 IDecl = ImpDecl->getClassInterface();
732 }
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000733 if (!IDecl ||
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000734 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
735 migrateFactoryMethod(Ctx, CDecl, OM);
Fariborz Jahanian71221352013-07-23 22:42:28 +0000736 return;
Fariborz Jahanian280954a2013-07-24 18:31:42 +0000737 }
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000738 ReplaceWithInstancetype(*this, OM);
Fariborz Jahanian71221352013-07-23 22:42:28 +0000739}
740
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +0000741static bool TypeIsInnerPointer(QualType T) {
742 if (!T->isAnyPointerType())
743 return false;
744 if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
745 T->isBlockPointerType() || ento::coreFoundation::isCFObjectRef(T))
746 return false;
747 return true;
748}
749
750void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
751 ObjCMethodDecl *OM) {
752 if (OM->hasAttr<ObjCReturnsInnerPointerAttr>())
753 return;
754
755 QualType RT = OM->getResultType();
756 if (!TypeIsInnerPointer(RT) ||
757 !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
758 return;
759
760 edit::Commit commit(*Editor);
761 commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER");
762 Editor->commit(commit);
763}
764
765void ObjCMigrateASTConsumer::migrateMethods(ASTContext &Ctx,
Fariborz Jahanian71221352013-07-23 22:42:28 +0000766 ObjCContainerDecl *CDecl) {
767 // migrate methods which can have instancetype as their result type.
768 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
769 MEnd = CDecl->meth_end();
770 M != MEnd; ++M) {
771 ObjCMethodDecl *Method = (*M);
772 migrateMethodInstanceType(Ctx, CDecl, Method);
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +0000773 migrateNsReturnsInnerPointer(Ctx, Method);
Fariborz Jahanian71221352013-07-23 22:42:28 +0000774 }
775}
776
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000777void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
778 ObjCContainerDecl *CDecl,
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000779 ObjCMethodDecl *OM,
780 ObjCInstanceTypeFamily OIT_Family) {
Fariborz Jahanian3bfc35e2013-08-02 22:34:18 +0000781 if (OM->isInstanceMethod() ||
782 OM->getResultType() == Ctx.getObjCInstanceType() ||
783 !OM->getResultType()->isObjCIdType())
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000784 return;
785
786 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
787 // NSYYYNamE with matching names be at least 3 characters long.
788 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
789 if (!IDecl) {
790 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
791 IDecl = CatDecl->getClassInterface();
792 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
793 IDecl = ImpDecl->getClassInterface();
794 }
795 if (!IDecl)
796 return;
797
798 std::string StringClassName = IDecl->getName();
799 StringRef LoweredClassName(StringClassName);
800 std::string StringLoweredClassName = LoweredClassName.lower();
801 LoweredClassName = StringLoweredClassName;
802
803 IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +0000804 // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
805 if (!MethodIdName)
806 return;
807
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000808 std::string MethodName = MethodIdName->getName();
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000809 if (OIT_Family == OIT_Singleton) {
810 StringRef STRefMethodName(MethodName);
811 size_t len = 0;
812 if (STRefMethodName.startswith("standard"))
813 len = strlen("standard");
814 else if (STRefMethodName.startswith("shared"))
815 len = strlen("shared");
816 else if (STRefMethodName.startswith("default"))
817 len = strlen("default");
818 else
819 return;
820 MethodName = STRefMethodName.substr(len);
821 }
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000822 std::string MethodNameSubStr = MethodName.substr(0, 3);
823 StringRef MethodNamePrefix(MethodNameSubStr);
824 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
825 MethodNamePrefix = StringLoweredMethodNamePrefix;
826 size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
827 if (Ix == StringRef::npos)
828 return;
829 std::string ClassNamePostfix = LoweredClassName.substr(Ix);
830 StringRef LoweredMethodName(MethodName);
831 std::string StringLoweredMethodName = LoweredMethodName.lower();
832 LoweredMethodName = StringLoweredMethodName;
833 if (!LoweredMethodName.startswith(ClassNamePostfix))
834 return;
835 ReplaceWithInstancetype(*this, OM);
836}
837
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +0000838static bool IsVoidStarType(QualType Ty) {
839 if (!Ty->isPointerType())
840 return false;
841
842 while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
843 Ty = TD->getDecl()->getUnderlyingType();
844
845 // Is the type void*?
846 const PointerType* PT = Ty->getAs<PointerType>();
847 if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
848 return true;
849 return IsVoidStarType(PT->getPointeeType());
850}
851
Fariborz Jahanian94279392013-08-20 18:54:39 +0000852/// AuditedType - This routine audits the type AT and returns false if it is one of known
853/// CF object types or of the "void *" variety. It returns true if we don't care about the type
854/// such as a non-pointer or pointers which have no ownership issues (such as "int *").
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000855static bool AuditedType (QualType AT) {
856 if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000857 return true;
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000858 // FIXME. There isn't much we can say about CF pointer type; or is there?
Fariborz Jahanian94279392013-08-20 18:54:39 +0000859 if (ento::coreFoundation::isCFObjectRef(AT) ||
860 IsVoidStarType(AT) ||
861 // If an ObjC object is type, assuming that it is not a CF function and
862 // that it is an un-audited function.
Fariborz Jahanian2e9c19c2013-08-22 22:27:36 +0000863 AT->isObjCObjectPointerType() || AT->isObjCBuiltinType())
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000864 return false;
Fariborz Jahanian94279392013-08-20 18:54:39 +0000865 // All other pointers are assumed audited as harmless.
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000866 return true;
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +0000867}
868
Fariborz Jahanian301b5212013-08-20 22:42:13 +0000869void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
Fariborz Jahanian926fafb2013-08-22 18:35:27 +0000870 if (CFFunctionIBCandidates.empty())
871 return;
Fariborz Jahanian301b5212013-08-20 22:42:13 +0000872 if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
873 CFFunctionIBCandidates.clear();
Fariborz Jahanianb8343522013-08-20 23:35:26 +0000874 FileId = 0;
Fariborz Jahanian301b5212013-08-20 22:42:13 +0000875 return;
876 }
877 // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
Fariborz Jahanian926fafb2013-08-22 18:35:27 +0000878 const Decl *FirstFD = CFFunctionIBCandidates[0];
879 const Decl *LastFD =
880 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
Fariborz Jahanian301b5212013-08-20 22:42:13 +0000881 const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
882 edit::Commit commit(*Editor);
883 commit.insertBefore(FirstFD->getLocStart(), PragmaString);
884 PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
885 SourceLocation EndLoc = LastFD->getLocEnd();
886 // get location just past end of function location.
887 EndLoc = PP.getLocForEndOfToken(EndLoc);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +0000888 if (isa<FunctionDecl>(LastFD)) {
889 // For Methods, EndLoc points to the ending semcolon. So,
890 // not of these extra work is needed.
891 Token Tok;
892 // get locaiton of token that comes after end of function.
893 bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
894 if (!Failed)
895 EndLoc = Tok.getLocation();
896 }
Fariborz Jahanian301b5212013-08-20 22:42:13 +0000897 commit.insertAfterToken(EndLoc, PragmaString);
898 Editor->commit(commit);
Fariborz Jahanianb8343522013-08-20 23:35:26 +0000899 FileId = 0;
Fariborz Jahanian301b5212013-08-20 22:42:13 +0000900 CFFunctionIBCandidates.clear();
901}
902
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +0000903void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
904 if (Decl->hasAttr<CFAuditedTransferAttr>()) {
Fariborz Jahanianc6dfd3f2013-08-19 22:00:50 +0000905 assert(CFFunctionIBCandidates.empty() &&
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +0000906 "Cannot have audited functions/methods inside user "
Fariborz Jahanianc6dfd3f2013-08-19 22:00:50 +0000907 "provided CF_IMPLICIT_BRIDGING_ENABLE");
908 return;
909 }
910
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +0000911 // Finction must be annotated first.
Fariborz Jahanian89f6d102013-09-04 00:10:06 +0000912 if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
913 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
914 if (AuditKind == CF_BRIDGING_ENABLE) {
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000915 CFFunctionIBCandidates.push_back(Decl);
916 if (!FileId)
917 FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue();
918 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +0000919 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
920 if (!CFFunctionIBCandidates.empty()) {
921 CFFunctionIBCandidates.push_back(Decl);
922 if (!FileId)
923 FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue();
924 }
925 }
926 else
927 AnnotateImplicitBridging(Ctx);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000928 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +0000929 else {
930 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
Fariborz Jahanian301b5212013-08-20 22:42:13 +0000931 AnnotateImplicitBridging(Ctx);
Fariborz Jahanian89f6d102013-09-04 00:10:06 +0000932 }
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +0000933}
934
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000935void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
936 const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +0000937 const FunctionDecl *FuncDecl,
938 bool ResultAnnotated) {
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000939 // Annotate function.
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +0000940 if (!ResultAnnotated) {
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000941 RetEffect Ret = CE.getReturnValue();
942 const char *AnnotationString = 0;
943 if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) {
944 if (Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
945 AnnotationString = " CF_RETURNS_RETAINED";
946 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +0000947 else if (Ret.getObjKind() == RetEffect::CF && Ret.notOwned()) {
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000948 if (Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
949 AnnotationString = " CF_RETURNS_NOT_RETAINED";
950 }
951 if (AnnotationString) {
952 edit::Commit commit(*Editor);
953 commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString);
954 Editor->commit(commit);
955 }
Fariborz Jahanian84ac1de2013-08-15 21:44:38 +0000956 }
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000957 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
958 unsigned i = 0;
959 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
960 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
Fariborz Jahanianb918d7a2013-08-21 19:37:47 +0000961 const ParmVarDecl *pd = *pi;
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +0000962 ArgEffect AE = AEArgs[i];
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000963 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
964 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
965 edit::Commit commit(*Editor);
966 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
967 Editor->commit(commit);
Fariborz Jahanian94279392013-08-20 18:54:39 +0000968 }
Fariborz Jahanian84ac1de2013-08-15 21:44:38 +0000969 }
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000970}
971
972
973ObjCMigrateASTConsumer::CF_BRIDGING_KIND
974 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
975 ASTContext &Ctx,
976 const FunctionDecl *FuncDecl) {
977 if (FuncDecl->hasBody())
978 return CF_BRIDGING_NONE;
979
980 CallEffects CE = CallEffects::getEffect(FuncDecl);
981 bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
982 FuncDecl->getAttr<CFReturnsNotRetainedAttr>());
983
984 // Trivial case of when funciton is annotated and has no argument.
985 if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
986 return CF_BRIDGING_NONE;
987
988 bool ReturnCFAudited = false;
989 if (!FuncIsReturnAnnotated) {
990 RetEffect Ret = CE.getReturnValue();
991 if (Ret.getObjKind() == RetEffect::CF &&
Fariborz Jahanian89f6d102013-09-04 00:10:06 +0000992 (Ret.isOwned() || Ret.notOwned()))
Fariborz Jahanian63ffce22013-08-27 22:42:30 +0000993 ReturnCFAudited = true;
994 else if (!AuditedType(FuncDecl->getResultType()))
995 return CF_BRIDGING_NONE;
996 }
997
998 // At this point result type is audited for potential inclusion.
999 // Now, how about argument types.
1000 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1001 unsigned i = 0;
1002 bool ArgCFAudited = false;
1003 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1004 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1005 const ParmVarDecl *pd = *pi;
1006 ArgEffect AE = AEArgs[i];
1007 if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
1008 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>())
1009 ArgCFAudited = true;
1010 else if (AE == IncRef)
1011 ArgCFAudited = true;
1012 }
1013 else {
1014 QualType AT = pd->getType();
1015 if (!AuditedType(AT)) {
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001016 AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001017 return CF_BRIDGING_NONE;
1018 }
1019 }
1020 }
1021 if (ReturnCFAudited || ArgCFAudited)
1022 return CF_BRIDGING_ENABLE;
1023
1024 return CF_BRIDGING_MAY_INCLUDE;
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +00001025}
1026
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001027void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
1028 ObjCContainerDecl *CDecl) {
1029 if (!isa<ObjCInterfaceDecl>(CDecl))
1030 return;
1031
1032 // migrate methods which can have instancetype as their result type.
1033 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
1034 MEnd = CDecl->meth_end();
1035 M != MEnd; ++M) {
1036 ObjCMethodDecl *Method = (*M);
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +00001037 migrateCFAnnotation(Ctx, Method);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001038 }
1039}
1040
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001041void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1042 const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001043 const ObjCMethodDecl *MethodDecl,
1044 bool ResultAnnotated) {
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001045 // Annotate function.
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001046 if (!ResultAnnotated) {
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001047 RetEffect Ret = CE.getReturnValue();
1048 const char *AnnotationString = 0;
1049 if (Ret.getObjKind() == RetEffect::CF && Ret.isOwned()) {
1050 if (Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
1051 AnnotationString = " CF_RETURNS_RETAINED";
1052 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001053 else if (Ret.getObjKind() == RetEffect::CF && Ret.notOwned()) {
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001054 if (Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
1055 AnnotationString = " CF_RETURNS_NOT_RETAINED";
1056 }
1057 if (AnnotationString) {
1058 edit::Commit commit(*Editor);
1059 commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
1060 Editor->commit(commit);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001061 }
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001062 }
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001063 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1064 unsigned i = 0;
1065 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1066 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1067 const ParmVarDecl *pd = *pi;
1068 ArgEffect AE = AEArgs[i];
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001069 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
1070 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
1071 edit::Commit commit(*Editor);
1072 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1073 Editor->commit(commit);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001074 }
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001075 }
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001076}
1077
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001078void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001079 ASTContext &Ctx,
1080 const ObjCMethodDecl *MethodDecl) {
1081 if (MethodDecl->hasBody())
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001082 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001083
1084 CallEffects CE = CallEffects::getEffect(MethodDecl);
1085 bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
1086 MethodDecl->getAttr<CFReturnsNotRetainedAttr>());
1087
1088 // Trivial case of when funciton is annotated and has no argument.
1089 if (MethodIsReturnAnnotated &&
1090 (MethodDecl->param_begin() == MethodDecl->param_end()))
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001091 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001092
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001093 if (!MethodIsReturnAnnotated) {
1094 RetEffect Ret = CE.getReturnValue();
Fariborz Jahanian8b102302013-09-04 16:43:57 +00001095 if (Ret.getObjKind() == RetEffect::CF && (Ret.isOwned() || Ret.notOwned())) {
1096 AddCFAnnotations(Ctx, CE, MethodDecl, false);
1097 return;
1098 }
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001099 else if (!AuditedType(MethodDecl->getResultType()))
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001100 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001101 }
1102
1103 // At this point result type is either annotated or audited.
1104 // Now, how about argument types.
1105 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1106 unsigned i = 0;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001107 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1108 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1109 const ParmVarDecl *pd = *pi;
1110 ArgEffect AE = AEArgs[i];
Fariborz Jahanian8b102302013-09-04 16:43:57 +00001111 if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef ||
1112 !AuditedType(pd->getType())) {
1113 AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
1114 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001115 }
1116 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001117 return;
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +00001118}
1119
Ted Kremenekf7639e12012-03-06 20:06:33 +00001120namespace {
1121
1122class RewritesReceiver : public edit::EditsReceiver {
1123 Rewriter &Rewrite;
1124
1125public:
1126 RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
1127
1128 virtual void insert(SourceLocation loc, StringRef text) {
1129 Rewrite.InsertText(loc, text);
1130 }
1131 virtual void replace(CharSourceRange range, StringRef text) {
1132 Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
1133 }
1134};
1135
1136}
1137
1138void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
Fariborz Jahaniana7437f02013-07-03 23:05:00 +00001139
1140 TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001141 if (MigrateProperty) {
Fariborz Jahaniand83ef842013-07-09 16:59:14 +00001142 for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
1143 D != DEnd; ++D) {
Fariborz Jahanianb8343522013-08-20 23:35:26 +00001144 if (unsigned FID =
1145 PP.getSourceManager().getFileID((*D)->getLocation()).getHashValue())
1146 if (FileId && FileId != FID) {
1147 assert(!CFFunctionIBCandidates.empty());
1148 AnnotateImplicitBridging(Ctx);
1149 }
1150
Fariborz Jahaniand83ef842013-07-09 16:59:14 +00001151 if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
1152 migrateObjCInterfaceDecl(Ctx, CDecl);
Fariborz Jahanian1be01532013-07-12 22:32:19 +00001153 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
1154 ObjCProtocolDecls.insert(PDecl);
1155 else if (const ObjCImplementationDecl *ImpDecl =
1156 dyn_cast<ObjCImplementationDecl>(*D))
1157 migrateProtocolConformance(Ctx, ImpDecl);
Fariborz Jahanian92463272013-07-18 20:11:45 +00001158 else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
1159 DeclContext::decl_iterator N = D;
1160 ++N;
Fariborz Jahanian008ef722013-07-19 17:44:32 +00001161 if (N != DEnd)
1162 if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N))
1163 migrateNSEnumDecl(Ctx, ED, TD);
Fariborz Jahanian92463272013-07-18 20:11:45 +00001164 }
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +00001165 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D))
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +00001166 migrateCFAnnotation(Ctx, FD);
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +00001167
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001168 if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
1169 // migrate methods which can have instancetype as their result type.
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +00001170 migrateMethods(Ctx, CDecl);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001171 // annotate methods with CF annotations.
1172 migrateARCSafeAnnotation(Ctx, CDecl);
1173 }
Fariborz Jahaniand83ef842013-07-09 16:59:14 +00001174 }
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001175 AnnotateImplicitBridging(Ctx);
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001176 }
Fariborz Jahaniana7437f02013-07-03 23:05:00 +00001177
David Blaikiebbafb8a2012-03-11 07:00:24 +00001178 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
Ted Kremenekf7639e12012-03-06 20:06:33 +00001179 RewritesReceiver Rec(rewriter);
1180 Editor->applyRewrites(Rec);
1181
1182 for (Rewriter::buffer_iterator
1183 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
1184 FileID FID = I->first;
1185 RewriteBuffer &buf = I->second;
1186 const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
1187 assert(file);
Dmitri Gribenkof8579502013-01-12 19:30:44 +00001188 SmallString<512> newText;
Ted Kremenekf7639e12012-03-06 20:06:33 +00001189 llvm::raw_svector_ostream vecOS(newText);
1190 buf.write(vecOS);
1191 vecOS.flush();
1192 llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
1193 StringRef(newText.data(), newText.size()), file->getName());
Dmitri Gribenkof8579502013-01-12 19:30:44 +00001194 SmallString<64> filePath(file->getName());
Ted Kremenekf7639e12012-03-06 20:06:33 +00001195 FileMgr.FixupRelativePath(filePath);
1196 Remapper.remap(filePath.str(), memBuf);
1197 }
1198
1199 if (IsOutputFile) {
1200 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
1201 } else {
1202 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
1203 }
1204}
1205
1206bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
Argyrios Kyrtzidisb4822602012-05-24 16:48:23 +00001207 CI.getDiagnostics().setIgnoreAllWarnings(true);
Ted Kremenekf7639e12012-03-06 20:06:33 +00001208 return true;
1209}
1210
1211ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
1212 StringRef InFile) {
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +00001213 PPConditionalDirectiveRecord *
1214 PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
1215 CI.getPreprocessor().addPPCallbacks(PPRec);
Ted Kremenekf7639e12012-03-06 20:06:33 +00001216 return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
1217 /*MigrateLiterals=*/true,
1218 /*MigrateSubscripting=*/true,
Fariborz Jahaniand83ef842013-07-09 16:59:14 +00001219 /*MigrateProperty*/true,
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +00001220 /*MigrateReadonlyProperty*/true,
Ted Kremenekf7639e12012-03-06 20:06:33 +00001221 Remapper,
1222 CI.getFileManager(),
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +00001223 PPRec,
Fariborz Jahaniana7437f02013-07-03 23:05:00 +00001224 CI.getPreprocessor(),
Ted Kremenekf7639e12012-03-06 20:06:33 +00001225 /*isOutputFile=*/true);
1226}