blob: 0f7b4c2bbd08f813c2acf428e686792687f74698 [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 Jahanian92f72422013-09-17 19:00:30 +000046 void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D);
Fariborz Jahanian1be01532013-07-12 22:32:19 +000047 void migrateProtocolConformance(ASTContext &Ctx,
48 const ObjCImplementationDecl *ImpDecl);
Fariborz Jahanian059e05e2013-10-15 00:00:28 +000049 void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +000050 bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
Fariborz Jahanian92463272013-07-18 20:11:45 +000051 const TypedefDecl *TypedefDcl);
Fariborz Jahanian8c45e282013-10-02 22:49:59 +000052 void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
Fariborz Jahanian670ef262013-07-23 23:34:42 +000053 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
54 ObjCMethodDecl *OM);
Fariborz Jahanian92f72422013-09-17 19:00:30 +000055 bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +000056 void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
Fariborz Jahanian10b74352013-09-24 20:20:52 +000057 void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
Fariborz Jahanianc4291852013-08-02 18:00:53 +000058 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
Fariborz Jahanian9275c682013-08-02 20:54:18 +000059 ObjCMethodDecl *OM,
60 ObjCInstanceTypeFamily OIT_Family = OIT_None);
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000061
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +000062 void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +000063 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +000064 const FunctionDecl *FuncDecl, bool ResultAnnotated);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +000065 void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +000066 const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +000067
Fariborz Jahanian301b5212013-08-20 22:42:13 +000068 void AnnotateImplicitBridging(ASTContext &Ctx);
69
Fariborz Jahanian63ffce22013-08-27 22:42:30 +000070 CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
71 const FunctionDecl *FuncDecl);
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +000072
Fariborz Jahanian926fafb2013-08-22 18:35:27 +000073 void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
74
Fariborz Jahanian89f6d102013-09-04 00:10:06 +000075 void migrateAddMethodAnnotation(ASTContext &Ctx,
76 const ObjCMethodDecl *MethodDecl);
Ted Kremenekf7639e12012-03-06 20:06:33 +000077public:
78 std::string MigrateDir;
Fariborz Jahanian182486c2013-10-02 17:08:12 +000079 unsigned ASTMigrateActions;
Fariborz Jahanianb8343522013-08-20 23:35:26 +000080 unsigned FileId;
Fariborz Jahanian059e05e2013-10-15 00:00:28 +000081 const TypedefDecl *NSIntegerTypedefed;
82 const TypedefDecl *NSUIntegerTypedefed;
Dmitri Gribenkof8579502013-01-12 19:30:44 +000083 OwningPtr<NSAPI> NSAPIObj;
84 OwningPtr<edit::EditedSource> Editor;
Ted Kremenekf7639e12012-03-06 20:06:33 +000085 FileRemapper &Remapper;
86 FileManager &FileMgr;
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +000087 const PPConditionalDirectiveRecord *PPRec;
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000088 Preprocessor &PP;
Ted Kremenekf7639e12012-03-06 20:06:33 +000089 bool IsOutputFile;
Fariborz Jahanian1be01532013-07-12 22:32:19 +000090 llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
Fariborz Jahanian926fafb2013-08-22 18:35:27 +000091 llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
Fariborz Jahanian1be01532013-07-12 22:32:19 +000092
Ted Kremenekf7639e12012-03-06 20:06:33 +000093 ObjCMigrateASTConsumer(StringRef migrateDir,
Fariborz Jahanian182486c2013-10-02 17:08:12 +000094 unsigned astMigrateActions,
Ted Kremenekf7639e12012-03-06 20:06:33 +000095 FileRemapper &remapper,
96 FileManager &fileMgr,
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +000097 const PPConditionalDirectiveRecord *PPRec,
Fariborz Jahaniana7437f02013-07-03 23:05:00 +000098 Preprocessor &PP,
Ted Kremenekf7639e12012-03-06 20:06:33 +000099 bool isOutputFile = false)
100 : MigrateDir(migrateDir),
Fariborz Jahanian182486c2013-10-02 17:08:12 +0000101 ASTMigrateActions(astMigrateActions),
Fariborz Jahanian059e05e2013-10-15 00:00:28 +0000102 FileId(0), NSIntegerTypedefed(0), NSUIntegerTypedefed(0),
103 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
Ted Kremenekf7639e12012-03-06 20:06:33 +0000104 IsOutputFile(isOutputFile) { }
105
106protected:
107 virtual void Initialize(ASTContext &Context) {
108 NSAPIObj.reset(new NSAPI(Context));
109 Editor.reset(new edit::EditedSource(Context.getSourceManager(),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000110 Context.getLangOpts(),
Fariborz Jahanian8f5225b2013-10-01 21:16:29 +0000111 PPRec, false));
Ted Kremenekf7639e12012-03-06 20:06:33 +0000112 }
113
114 virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
115 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
116 migrateDecl(*I);
117 return true;
118 }
119 virtual void HandleInterestingDecl(DeclGroupRef DG) {
120 // Ignore decls from the PCH.
121 }
122 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
123 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
124 }
125
126 virtual void HandleTranslationUnit(ASTContext &Ctx);
127};
128
129}
130
131ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
Fariborz Jahanian182486c2013-10-02 17:08:12 +0000132 StringRef migrateDir,
133 unsigned migrateAction)
Ted Kremenekf7639e12012-03-06 20:06:33 +0000134 : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
Fariborz Jahanian182486c2013-10-02 17:08:12 +0000135 ObjCMigAction(migrateAction),
Ted Kremenekf7639e12012-03-06 20:06:33 +0000136 CompInst(0) {
137 if (MigrateDir.empty())
138 MigrateDir = "."; // user current directory if none is given.
139}
140
141ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
142 StringRef InFile) {
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +0000143 PPConditionalDirectiveRecord *
144 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
145 CompInst->getPreprocessor().addPPCallbacks(PPRec);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000146 ASTConsumer *
147 WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
148 ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
Fariborz Jahanian182486c2013-10-02 17:08:12 +0000149 ObjCMigAction,
Ted Kremenekf7639e12012-03-06 20:06:33 +0000150 Remapper,
151 CompInst->getFileManager(),
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000152 PPRec,
153 CompInst->getPreprocessor());
Ted Kremenekf7639e12012-03-06 20:06:33 +0000154 ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
155 return new MultiplexConsumer(Consumers);
156}
157
158bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
159 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
160 /*ignoreIfFilesChanges=*/true);
161 CompInst = &CI;
162 CI.getDiagnostics().setIgnoreAllWarnings(true);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000163 return true;
164}
165
166namespace {
167class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
168 ObjCMigrateASTConsumer &Consumer;
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000169 ParentMap &PMap;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000170
171public:
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000172 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
173 : Consumer(consumer), PMap(PMap) { }
Ted Kremenekf7639e12012-03-06 20:06:33 +0000174
175 bool shouldVisitTemplateInstantiations() const { return false; }
176 bool shouldWalkTypesOfTypeLocs() const { return false; }
177
178 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
Fariborz Jahanian182486c2013-10-02 17:08:12 +0000179 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
Ted Kremenekf7639e12012-03-06 20:06:33 +0000180 edit::Commit commit(*Consumer.Editor);
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000181 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000182 Consumer.Editor->commit(commit);
183 }
184
Fariborz Jahanian182486c2013-10-02 17:08:12 +0000185 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
Ted Kremenekf7639e12012-03-06 20:06:33 +0000186 edit::Commit commit(*Consumer.Editor);
187 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
188 Consumer.Editor->commit(commit);
189 }
190
191 return true;
192 }
193
194 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
195 // Do depth first; we want to rewrite the subexpressions first so that if
196 // we have to move expressions we will move them already rewritten.
197 for (Stmt::child_range range = E->children(); range; ++range)
198 if (!TraverseStmt(*range))
199 return false;
200
201 return WalkUpFromObjCMessageExpr(E);
202 }
203};
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000204
205class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
206 ObjCMigrateASTConsumer &Consumer;
207 OwningPtr<ParentMap> PMap;
208
209public:
210 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
211
212 bool shouldVisitTemplateInstantiations() const { return false; }
213 bool shouldWalkTypesOfTypeLocs() const { return false; }
214
215 bool TraverseStmt(Stmt *S) {
216 PMap.reset(new ParentMap(S));
217 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
218 return true;
219 }
220};
Ted Kremenekf7639e12012-03-06 20:06:33 +0000221}
222
223void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
224 if (!D)
225 return;
226 if (isa<ObjCMethodDecl>(D))
227 return; // Wait for the ObjC container declaration.
228
Argyrios Kyrtzidis6b4f3412013-01-16 23:54:48 +0000229 BodyMigrator(*this).TraverseDecl(D);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000230}
231
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000232static void append_attr(std::string &PropertyString, const char *attr,
233 bool &LParenAdded) {
234 if (!LParenAdded) {
235 PropertyString += "(";
236 LParenAdded = true;
237 }
238 else
239 PropertyString += ", ";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000240 PropertyString += attr;
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000241}
242
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000243static
244void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
245 const std::string& TypeString,
246 const char *name) {
247 const char *argPtr = TypeString.c_str();
248 int paren = 0;
249 while (*argPtr) {
250 switch (*argPtr) {
251 case '(':
252 PropertyString += *argPtr;
253 paren++;
254 break;
255 case ')':
256 PropertyString += *argPtr;
257 paren--;
258 break;
259 case '^':
Fariborz Jahanian3c593d62013-10-08 21:32:16 +0000260 case '*':
261 PropertyString += (*argPtr);
262 if (paren == 1) {
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000263 PropertyString += name;
Fariborz Jahanian3c593d62013-10-08 21:32:16 +0000264 name = "";
265 }
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000266 break;
267 default:
268 PropertyString += *argPtr;
269 break;
270 }
271 argPtr++;
272 }
273}
274
275
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000276static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter,
277 const ObjCMethodDecl *Setter,
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000278 const NSAPI &NS, edit::Commit &commit,
Fariborz Jahanian20a11242013-10-09 19:06:08 +0000279 unsigned LengthOfPrefix,
280 bool Atomic) {
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000281 ASTContext &Context = NS.getASTContext();
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000282 bool LParenAdded = false;
283 std::string PropertyString = "@property ";
284 if (!Atomic) {
285 PropertyString += "(nonatomic";
286 LParenAdded = true;
287 }
288
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000289 std::string PropertyNameString = Getter->getNameAsString();
290 StringRef PropertyName(PropertyNameString);
Fariborz Jahanianca399602013-09-11 17:05:15 +0000291 if (LengthOfPrefix > 0) {
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000292 if (!LParenAdded) {
293 PropertyString += "(getter=";
294 LParenAdded = true;
295 }
296 else
297 PropertyString += ", getter=";
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000298 PropertyString += PropertyNameString;
299 }
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000300 // Property with no setter may be suggested as a 'readonly' property.
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000301 if (!Setter) {
302 if (!LParenAdded) {
303 PropertyString += "(readonly";
304 LParenAdded = true;
305 }
306 else
307 append_attr(PropertyString, "readonly", LParenAdded);
308 }
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000309
Fariborz Jahanian33304e302013-10-16 18:52:17 +0000310 // Short circuit 'delegate' properties that contain the name "delegate" or
311 // "dataSource", or have exact name "target" to have 'assign' attribute.
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000312 if (PropertyName.equals("target") ||
313 (PropertyName.find("delegate") != StringRef::npos) ||
314 (PropertyName.find("dataSource") != StringRef::npos))
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000315 append_attr(PropertyString, "assign", LParenAdded);
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000316 else if (Setter) {
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000317 const ParmVarDecl *argDecl = *Setter->param_begin();
318 QualType ArgType = Context.getCanonicalType(argDecl->getType());
319 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
320 bool RetainableObject = ArgType->isObjCRetainableType();
321 if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
322 if (const ObjCObjectPointerType *ObjPtrTy =
323 ArgType->getAs<ObjCObjectPointerType>()) {
324 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
325 if (IDecl &&
326 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000327 append_attr(PropertyString, "copy", LParenAdded);
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000328 else
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000329 append_attr(PropertyString, "retain", LParenAdded);
Fariborz Jahanian447b15e2013-08-21 18:49:03 +0000330 }
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000331 else if (ArgType->isBlockPointerType())
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000332 append_attr(PropertyString, "copy", LParenAdded);
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000333 } else if (propertyLifetime == Qualifiers::OCL_Weak)
334 // TODO. More precise determination of 'weak' attribute requires
335 // looking into setter's implementation for backing weak ivar.
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000336 append_attr(PropertyString, "weak", LParenAdded);
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000337 else if (RetainableObject)
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000338 append_attr(PropertyString,
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000339 ArgType->isBlockPointerType() ? "copy" : "retain", LParenAdded);
Fariborz Jahaniancf387c62013-08-06 18:06:23 +0000340 }
Fariborz Jahanian4a8865b2013-10-16 19:48:23 +0000341 if (LParenAdded)
342 PropertyString += ')';
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000343 QualType RT = Getter->getResultType();
344 if (!isa<TypedefType>(RT)) {
345 // strip off any ARC lifetime qualifier.
346 QualType CanResultTy = Context.getCanonicalType(RT);
347 if (CanResultTy.getQualifiers().hasObjCLifetime()) {
348 Qualifiers Qs = CanResultTy.getQualifiers();
349 Qs.removeObjCLifetime();
350 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
351 }
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000352 }
353 PropertyString += " ";
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000354 PrintingPolicy SubPolicy(Context.getPrintingPolicy());
355 SubPolicy.SuppressStrongLifetime = true;
Fariborz Jahaniande557f82013-10-09 17:37:28 +0000356 SubPolicy.SuppressLifetimeQualifiers = true;
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000357 std::string TypeString = RT.getAsString(SubPolicy);
Fariborz Jahanianca399602013-09-11 17:05:15 +0000358 if (LengthOfPrefix > 0) {
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000359 // property name must strip off "is" and lower case the first character
360 // after that; e.g. isContinuous will become continuous.
361 StringRef PropertyNameStringRef(PropertyNameString);
Fariborz Jahanianca399602013-09-11 17:05:15 +0000362 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000363 PropertyNameString = PropertyNameStringRef;
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000364 bool NoLowering = (isUppercase(PropertyNameString[0]) &&
365 PropertyNameString.size() > 1 &&
366 isUppercase(PropertyNameString[1]));
Fariborz Jahanian34fea362013-09-11 18:27:16 +0000367 if (!NoLowering)
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000368 PropertyNameString[0] = toLowercase(PropertyNameString[0]);
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000369 }
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000370 if (RT->isBlockPointerType() || RT->isFunctionPointerType())
371 MigrateBlockOrFunctionPointerTypeVariable(PropertyString,
372 TypeString,
373 PropertyNameString.c_str());
374 else {
375 char LastChar = TypeString[TypeString.size()-1];
376 PropertyString += TypeString;
377 if (LastChar != '*')
378 PropertyString += ' ';
Fariborz Jahaniancf2ff9b2013-08-08 20:51:58 +0000379 PropertyString += PropertyNameString;
Fariborz Jahanian02461d02013-10-08 20:14:24 +0000380 }
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000381 SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
382 Selector GetterSelector = Getter->getSelector();
383
384 SourceLocation EndGetterSelectorLoc =
385 StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000386 commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000387 EndGetterSelectorLoc),
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000388 PropertyString);
Fariborz Jahanian55d6e6c2013-08-28 23:22:46 +0000389 if (Setter) {
390 SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
391 // Get location past ';'
392 EndLoc = EndLoc.getLocWithOffset(1);
393 commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc));
394 }
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000395 return true;
396}
397
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000398void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
Fariborz Jahanian92f72422013-09-17 19:00:30 +0000399 ObjCContainerDecl *D) {
Fariborz Jahanian75226d52013-09-17 21:56:04 +0000400 if (D->isDeprecated())
401 return;
402
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000403 for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
404 M != MEnd; ++M) {
405 ObjCMethodDecl *Method = (*M);
Fariborz Jahanian75226d52013-09-17 21:56:04 +0000406 if (Method->isDeprecated())
407 continue;
Fariborz Jahanian10b74352013-09-24 20:20:52 +0000408 migrateProperty(Ctx, D, Method);
Fariborz Jahanian8c45e282013-10-02 22:49:59 +0000409 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
410 migrateNsReturnsInnerPointer(Ctx, Method);
Fariborz Jahanian10b74352013-09-24 20:20:52 +0000411 }
412 for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
413 E = D->prop_end(); P != E; ++P) {
414 ObjCPropertyDecl *Prop = *P;
Fariborz Jahanian8c45e282013-10-02 22:49:59 +0000415 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
416 !P->isDeprecated())
Fariborz Jahanian10b74352013-09-24 20:20:52 +0000417 migratePropertyNsReturnsInnerPointer(Ctx, Prop);
Fariborz Jahaniana7437f02013-07-03 23:05:00 +0000418 }
419}
420
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000421static bool
Fariborz Jahanian9a3512b2013-07-13 17:16:41 +0000422ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000423 const ObjCImplementationDecl *ImpDecl,
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000424 const ObjCInterfaceDecl *IDecl,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000425 ObjCProtocolDecl *Protocol) {
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000426 // In auto-synthesis, protocol properties are not synthesized. So,
427 // a conforming protocol must have its required properties declared
428 // in class interface.
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000429 bool HasAtleastOneRequiredProperty = false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000430 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
431 for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
432 E = PDecl->prop_end(); P != E; ++P) {
433 ObjCPropertyDecl *Property = *P;
434 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
435 continue;
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000436 HasAtleastOneRequiredProperty = true;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000437 DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
Fariborz Jahanian2bc3dda2013-07-16 21:59:42 +0000438 if (R.size() == 0) {
439 // Relax the rule and look into class's implementation for a synthesize
440 // or dynamic declaration. Class is implementing a property coming from
441 // another protocol. This still makes the target protocol as conforming.
442 if (!ImpDecl->FindPropertyImplDecl(
443 Property->getDeclName().getAsIdentifierInfo()))
444 return false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000445 }
Fariborz Jahanian2bc3dda2013-07-16 21:59:42 +0000446 else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
447 if ((ClassProperty->getPropertyAttributes()
448 != Property->getPropertyAttributes()) ||
449 !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
450 return false;
451 }
452 else
453 return false;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000454 }
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000455
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000456 // At this point, all required properties in this protocol conform to those
457 // declared in the class.
458 // Check that class implements the required methods of the protocol too.
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000459 bool HasAtleastOneRequiredMethod = false;
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000460 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
461 if (PDecl->meth_begin() == PDecl->meth_end())
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000462 return HasAtleastOneRequiredProperty;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000463 for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
464 MEnd = PDecl->meth_end(); M != MEnd; ++M) {
465 ObjCMethodDecl *MD = (*M);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000466 if (MD->isImplicit())
467 continue;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000468 if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
469 continue;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000470 DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000471 if (R.size() == 0)
472 return false;
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000473 bool match = false;
474 HasAtleastOneRequiredMethod = true;
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000475 for (unsigned I = 0, N = R.size(); I != N; ++I)
476 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
477 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
478 match = true;
479 break;
480 }
481 if (!match)
482 return false;
483 }
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000484 }
Fariborz Jahanian9e543af2013-07-22 23:50:04 +0000485 if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
486 return true;
487 return false;
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000488}
489
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000490static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
491 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
492 const NSAPI &NS, edit::Commit &commit) {
493 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
494 std::string ClassString;
495 SourceLocation EndLoc =
496 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
497
498 if (Protocols.empty()) {
499 ClassString = '<';
500 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
501 ClassString += ConformingProtocols[i]->getNameAsString();
502 if (i != (e-1))
503 ClassString += ", ";
504 }
505 ClassString += "> ";
506 }
507 else {
508 ClassString = ", ";
509 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
510 ClassString += ConformingProtocols[i]->getNameAsString();
511 if (i != (e-1))
512 ClassString += ", ";
513 }
514 ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
515 EndLoc = *PL;
516 }
517
518 commit.insertAfterToken(EndLoc, ClassString);
519 return true;
520}
521
522static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
523 const TypedefDecl *TypedefDcl,
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000524 const NSAPI &NS, edit::Commit &commit,
Fariborz Jahanianff3476e2013-08-30 17:46:01 +0000525 bool IsNSIntegerType,
526 bool NSOptions) {
527 std::string ClassString;
528 if (NSOptions)
529 ClassString = "typedef NS_OPTIONS(NSUInteger, ";
530 else
531 ClassString =
532 IsNSIntegerType ? "typedef NS_ENUM(NSInteger, "
533 : "typedef NS_ENUM(NSUInteger, ";
534
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000535 ClassString += TypedefDcl->getIdentifier()->getName();
536 ClassString += ')';
537 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
538 commit.replace(R, ClassString);
Fariborz Jahanian059e05e2013-10-15 00:00:28 +0000539 SourceLocation EndOfEnumDclLoc = EnumDcl->getLocEnd();
540 EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
541 NS.getASTContext(), /*IsDecl*/true);
542 if (!EndOfEnumDclLoc.isInvalid()) {
543 SourceRange EnumDclRange(EnumDcl->getLocStart(), EndOfEnumDclLoc);
544 commit.insertFromRange(TypedefDcl->getLocStart(), EnumDclRange);
545 }
546 else
547 return false;
548
549 SourceLocation EndTypedefDclLoc = TypedefDcl->getLocEnd();
550 EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
551 NS.getASTContext(), /*IsDecl*/true);
552 if (!EndTypedefDclLoc.isInvalid()) {
553 SourceRange TDRange(TypedefDcl->getLocStart(), EndTypedefDclLoc);
554 commit.remove(TDRange);
555 }
556 else
557 return false;
558
559 EndOfEnumDclLoc = trans::findLocationAfterSemi(EnumDcl->getLocEnd(), NS.getASTContext(),
Fariborz Jahanian1d27ffd2013-10-11 17:35:22 +0000560 /*IsDecl*/true);
Fariborz Jahanian059e05e2013-10-15 00:00:28 +0000561 if (!EndOfEnumDclLoc.isInvalid()) {
562 SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart();
563 // FIXME. This assumes that enum decl; is immediately preceeded by eoln.
564 // It is trying to remove the enum decl. lines entirely.
565 BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
566 commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000567 return true;
568 }
569 return false;
570}
571
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000572static bool rewriteToNSMacroDecl(const EnumDecl *EnumDcl,
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000573 const TypedefDecl *TypedefDcl,
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000574 const NSAPI &NS, edit::Commit &commit,
575 bool IsNSIntegerType) {
576 std::string ClassString =
577 IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, ";
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000578 ClassString += TypedefDcl->getIdentifier()->getName();
579 ClassString += ')';
580 SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart());
581 commit.replace(R, ClassString);
582 SourceLocation TypedefLoc = TypedefDcl->getLocEnd();
583 commit.remove(SourceRange(TypedefLoc, TypedefLoc));
584 return true;
585}
586
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000587static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000588 const EnumDecl *EnumDcl) {
589 bool PowerOfTwo = true;
Fariborz Jahanian02bdb162013-09-23 20:27:06 +0000590 bool AllHexdecimalEnumerator = true;
Fariborz Jahanianbe7bc112013-08-15 18:46:37 +0000591 uint64_t MaxPowerOfTwoVal = 0;
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000592 for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
593 EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
594 EnumConstantDecl *Enumerator = (*EI);
595 const Expr *InitExpr = Enumerator->getInitExpr();
596 if (!InitExpr) {
597 PowerOfTwo = false;
Fariborz Jahanian02bdb162013-09-23 20:27:06 +0000598 AllHexdecimalEnumerator = false;
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000599 continue;
600 }
Fariborz Jahanian6e1798e2013-09-17 23:32:51 +0000601 InitExpr = InitExpr->IgnoreParenCasts();
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000602 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
603 if (BO->isShiftOp() || BO->isBitwiseOp())
604 return true;
605
606 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
Fariborz Jahanianbe7bc112013-08-15 18:46:37 +0000607 if (PowerOfTwo && EnumVal) {
608 if (!llvm::isPowerOf2_64(EnumVal))
609 PowerOfTwo = false;
610 else if (EnumVal > MaxPowerOfTwoVal)
611 MaxPowerOfTwoVal = EnumVal;
612 }
Fariborz Jahanian02bdb162013-09-23 20:27:06 +0000613 if (AllHexdecimalEnumerator && EnumVal) {
614 bool FoundHexdecimalEnumerator = false;
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000615 SourceLocation EndLoc = Enumerator->getLocEnd();
616 Token Tok;
617 if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
618 if (Tok.isLiteral() && Tok.getLength() > 2) {
619 if (const char *StringLit = Tok.getLiteralData())
620 FoundHexdecimalEnumerator =
621 (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
622 }
Fariborz Jahanian02bdb162013-09-23 20:27:06 +0000623 if (!FoundHexdecimalEnumerator)
624 AllHexdecimalEnumerator = false;
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000625 }
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000626 }
Fariborz Jahanian02bdb162013-09-23 20:27:06 +0000627 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000628}
629
Fariborz Jahanian008ef722013-07-19 17:44:32 +0000630void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000631 const ObjCImplementationDecl *ImpDecl) {
632 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
Fariborz Jahanian75226d52013-09-17 21:56:04 +0000633 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000634 return;
635 // Find all implicit conforming protocols for this class
636 // and make them explicit.
637 llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
638 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000639 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000640
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000641 for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I =
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000642 ObjCProtocolDecls.begin(),
643 E = ObjCProtocolDecls.end(); I != E; ++I)
644 if (!ExplicitProtocols.count(*I))
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000645 PotentialImplicitProtocols.push_back(*I);
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000646
647 if (PotentialImplicitProtocols.empty())
648 return;
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000649
650 // go through list of non-optional methods and properties in each protocol
651 // in the PotentialImplicitProtocols list. If class implements every one of the
652 // methods and properties, then this class conforms to this protocol.
653 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
654 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
Fariborz Jahaniand36150d2013-07-15 21:22:08 +0000655 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
Fariborz Jahanian9eabf452013-07-13 00:04:20 +0000656 PotentialImplicitProtocols[i]))
657 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000658
659 if (ConformingProtocols.empty())
660 return;
Fariborz Jahaniancb7b8de2013-07-17 00:02:22 +0000661
662 // Further reduce number of conforming protocols. If protocol P1 is in the list
663 // protocol P2 (P2<P1>), No need to include P1.
664 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
665 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
666 bool DropIt = false;
667 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
668 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
669 ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
670 if (PDecl == TargetPDecl)
671 continue;
672 if (PDecl->lookupProtocolNamed(
673 TargetPDecl->getDeclName().getAsIdentifierInfo())) {
674 DropIt = true;
675 break;
676 }
677 }
678 if (!DropIt)
679 MinimalConformingProtocols.push_back(TargetPDecl);
680 }
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000681 edit::Commit commit(*Editor);
Fariborz Jahanian85e988b2013-07-18 22:17:33 +0000682 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
683 *NSAPIObj, commit);
Fariborz Jahanian5bd5aff2013-07-16 00:20:21 +0000684 Editor->commit(commit);
Fariborz Jahanian1be01532013-07-12 22:32:19 +0000685}
686
Fariborz Jahanian059e05e2013-10-15 00:00:28 +0000687void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
688 const TypedefDecl *TypedefDcl) {
689
690 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
691 if (NSAPIObj->isObjCNSIntegerType(qt))
692 NSIntegerTypedefed = TypedefDcl;
693 else if (NSAPIObj->isObjCNSUIntegerType(qt))
694 NSUIntegerTypedefed = TypedefDcl;
695}
696
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +0000697bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
Fariborz Jahanian92463272013-07-18 20:11:45 +0000698 const EnumDecl *EnumDcl,
699 const TypedefDecl *TypedefDcl) {
700 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
Fariborz Jahanian059e05e2013-10-15 00:00:28 +0000701 EnumDcl->isDeprecated())
702 return false;
703 if (!TypedefDcl) {
704 if (NSIntegerTypedefed) {
705 TypedefDcl = NSIntegerTypedefed;
706 NSIntegerTypedefed = 0;
707 }
708 else if (NSUIntegerTypedefed) {
709 TypedefDcl = NSUIntegerTypedefed;
710 NSUIntegerTypedefed = 0;
711 }
712 else
713 return false;
714 unsigned FileIdOfTypedefDcl =
715 PP.getSourceManager().getFileID(TypedefDcl->getLocation()).getHashValue();
716 unsigned FileIdOfEnumDcl =
717 PP.getSourceManager().getFileID(EnumDcl->getLocation()).getHashValue();
718 if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
719 return false;
720 }
721 if (TypedefDcl->isDeprecated())
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +0000722 return false;
Fariborz Jahanian92463272013-07-18 20:11:45 +0000723
724 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000725 bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt);
726 bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000727
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000728 if (!IsNSIntegerType && !IsNSUIntegerType) {
729 // Also check for typedef enum {...} TD;
730 if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
731 if (EnumTy->getDecl() == EnumDcl) {
Fariborz Jahaniana23f4fb2013-08-30 00:10:37 +0000732 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000733 if (NSOptions) {
734 if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +0000735 return false;
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000736 }
737 else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +0000738 return false;
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000739 edit::Commit commit(*Editor);
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000740 rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000741 Editor->commit(commit);
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000742 }
Fariborz Jahanianc1c44f62013-07-19 20:18:36 +0000743 }
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +0000744 return false;
Fariborz Jahaniand0f6f792013-07-22 18:53:45 +0000745 }
Fariborz Jahanian92463272013-07-18 20:11:45 +0000746
Fariborz Jahanianff3476e2013-08-30 17:46:01 +0000747 // We may still use NS_OPTIONS based on what we find in the enumertor list.
748 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
Fariborz Jahanian92463272013-07-18 20:11:45 +0000749 // NS_ENUM must be available.
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000750 if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition())
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +0000751 return false;
Fariborz Jahanianb0057bb2013-07-19 01:05:49 +0000752 // NS_OPTIONS must be available.
753 if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition())
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +0000754 return false;
Fariborz Jahanian92463272013-07-18 20:11:45 +0000755 edit::Commit commit(*Editor);
Fariborz Jahanian059e05e2013-10-15 00:00:28 +0000756 bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
757 commit, IsNSIntegerType, NSOptions);
Fariborz Jahanian92463272013-07-18 20:11:45 +0000758 Editor->commit(commit);
Fariborz Jahanian059e05e2013-10-15 00:00:28 +0000759 return Res;
Fariborz Jahanian92463272013-07-18 20:11:45 +0000760}
761
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000762static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
763 ObjCMethodDecl *OM) {
764 SourceRange R;
765 std::string ClassString;
766 if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
767 TypeLoc TL = TSInfo->getTypeLoc();
768 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
769 ClassString = "instancetype";
770 }
771 else {
772 R = SourceRange(OM->getLocStart(), OM->getLocStart());
773 ClassString = OM->isInstanceMethod() ? '-' : '+';
774 ClassString += " (instancetype)";
775 }
776 edit::Commit commit(*ASTC.Editor);
777 commit.replace(R, ClassString);
778 ASTC.Editor->commit(commit);
779}
780
Fariborz Jahanian7c87b432013-10-10 18:23:13 +0000781static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
782 ObjCMethodDecl *OM) {
783 ObjCInterfaceDecl *IDecl = OM->getClassInterface();
784 SourceRange R;
785 std::string ClassString;
786 if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
787 TypeLoc TL = TSInfo->getTypeLoc();
788 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
789 ClassString = IDecl->getName();
790 ClassString += "*";
791 }
792 }
793 else {
794 R = SourceRange(OM->getLocStart(), OM->getLocStart());
795 ClassString = "+ (";
796 ClassString += IDecl->getName(); ClassString += "*)";
797 }
798 edit::Commit commit(*ASTC.Editor);
799 commit.replace(R, ClassString);
800 ASTC.Editor->commit(commit);
801}
802
Fariborz Jahanian670ef262013-07-23 23:34:42 +0000803void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
804 ObjCContainerDecl *CDecl,
805 ObjCMethodDecl *OM) {
Fariborz Jahanian71221352013-07-23 22:42:28 +0000806 ObjCInstanceTypeFamily OIT_Family =
807 Selector::getInstTypeMethodFamily(OM->getSelector());
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000808
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000809 std::string ClassName;
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000810 switch (OIT_Family) {
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000811 case OIT_None:
812 migrateFactoryMethod(Ctx, CDecl, OM);
813 return;
Fariborz Jahanian7dd71432013-08-28 21:23:00 +0000814 case OIT_Array:
815 ClassName = "NSArray";
816 break;
817 case OIT_Dictionary:
818 ClassName = "NSDictionary";
819 break;
Fariborz Jahanian9275c682013-08-02 20:54:18 +0000820 case OIT_Singleton:
821 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000822 return;
Fariborz Jahanian1c900bc2013-09-18 20:35:47 +0000823 case OIT_Init:
824 if (OM->getResultType()->isObjCIdType())
825 ReplaceWithInstancetype(*this, OM);
826 return;
Fariborz Jahanian7c87b432013-10-10 18:23:13 +0000827 case OIT_ReturnsSelf:
828 migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
829 return;
Fariborz Jahanian631925f2013-07-23 23:55:55 +0000830 }
Fariborz Jahanian71221352013-07-23 22:42:28 +0000831 if (!OM->getResultType()->isObjCIdType())
832 return;
833
834 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
835 if (!IDecl) {
836 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
837 IDecl = CatDecl->getClassInterface();
838 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
839 IDecl = ImpDecl->getClassInterface();
840 }
Fariborz Jahanian267bae32013-07-24 19:18:37 +0000841 if (!IDecl ||
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000842 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
843 migrateFactoryMethod(Ctx, CDecl, OM);
Fariborz Jahanian71221352013-07-23 22:42:28 +0000844 return;
Fariborz Jahanian280954a2013-07-24 18:31:42 +0000845 }
Fariborz Jahanianc4291852013-08-02 18:00:53 +0000846 ReplaceWithInstancetype(*this, OM);
Fariborz Jahanian71221352013-07-23 22:42:28 +0000847}
848
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +0000849static bool TypeIsInnerPointer(QualType T) {
850 if (!T->isAnyPointerType())
851 return false;
852 if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
Fariborz Jahanian73466ca2013-09-26 21:43:47 +0000853 T->isBlockPointerType() || T->isFunctionPointerType() ||
854 ento::coreFoundation::isCFObjectRef(T))
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +0000855 return false;
Fariborz Jahanian9d5fffb2013-09-09 23:56:14 +0000856 // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
857 // is not an innter pointer type.
858 QualType OrigT = T;
859 while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr()))
860 T = TD->getDecl()->getUnderlyingType();
861 if (OrigT == T || !T->isPointerType())
862 return true;
863 const PointerType* PT = T->getAs<PointerType>();
864 QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
865 if (UPointeeT->isRecordType()) {
866 const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
867 if (!RecordTy->getDecl()->isCompleteDefinition())
868 return false;
869 }
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +0000870 return true;
871}
872
Fariborz Jahanian2ba62a72013-09-18 17:22:25 +0000873static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2) {
874 if (Decl1->hasAttrs() != Decl2->hasAttrs())
875 return false;
876
877 if (!Decl1->hasAttrs())
878 return true;
879
880 const AttrVec &Attrs1 = Decl1->getAttrs();
881 const AttrVec &Attrs2 = Decl2->getAttrs();
882 // This list is very small, so this need not be optimized.
883 for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
884 bool match = false;
885 for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
886 // Matching attribute kind only. We are not getting into
887 // details of the attributes. For all practical purposes
888 // this is sufficient.
889 if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
890 match = true;
891 break;
892 }
893 }
894 if (!match)
895 return false;
896 }
897 return true;
898}
899
Fariborz Jahanian5d783df2013-09-27 22:55:54 +0000900static bool IsValidIdentifier(ASTContext &Ctx,
901 const char *Name) {
902 if (!isIdentifierHead(Name[0]))
903 return false;
904 std::string NameString = Name;
905 NameString[0] = toLowercase(NameString[0]);
906 IdentifierInfo *II = &Ctx.Idents.get(NameString);
907 return II->getTokenID() == tok::identifier;
908}
909
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000910bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
Fariborz Jahanian92f72422013-09-17 19:00:30 +0000911 ObjCContainerDecl *D,
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000912 ObjCMethodDecl *Method) {
913 if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
914 Method->param_size() != 0)
915 return false;
916 // Is this method candidate to be a getter?
917 QualType GRT = Method->getResultType();
918 if (GRT->isVoidType())
919 return false;
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000920
921 Selector GetterSelector = Method->getSelector();
Fariborz Jahanian7391a7b5a2013-09-25 00:17:07 +0000922 ObjCInstanceTypeFamily OIT_Family =
923 Selector::getInstTypeMethodFamily(GetterSelector);
924
925 if (OIT_Family != OIT_None)
926 return false;
927
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000928 IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
929 Selector SetterSelector =
930 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
931 PP.getSelectorTable(),
932 getterName);
Fariborz Jahanian92f72422013-09-17 19:00:30 +0000933 ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
Fariborz Jahanianca399602013-09-11 17:05:15 +0000934 unsigned LengthOfPrefix = 0;
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000935 if (!SetterMethod) {
936 // try a different naming convention for getter: isXxxxx
937 StringRef getterNameString = getterName->getName();
Fariborz Jahanianca399602013-09-11 17:05:15 +0000938 bool IsPrefix = getterNameString.startswith("is");
Fariborz Jahanian4c3d9c52013-09-17 19:38:55 +0000939 // Note that we don't want to change an isXXX method of retainable object
940 // type to property (readonly or otherwise).
941 if (IsPrefix && GRT->isObjCRetainableType())
942 return false;
943 if (IsPrefix || getterNameString.startswith("get")) {
Fariborz Jahanianca399602013-09-11 17:05:15 +0000944 LengthOfPrefix = (IsPrefix ? 2 : 3);
945 const char *CGetterName = getterNameString.data() + LengthOfPrefix;
946 // Make sure that first character after "is" or "get" prefix can
947 // start an identifier.
Fariborz Jahanian5d783df2013-09-27 22:55:54 +0000948 if (!IsValidIdentifier(Ctx, CGetterName))
Fariborz Jahanianca399602013-09-11 17:05:15 +0000949 return false;
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000950 if (CGetterName[0] && isUppercase(CGetterName[0])) {
951 getterName = &Ctx.Idents.get(CGetterName);
952 SetterSelector =
953 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
954 PP.getSelectorTable(),
955 getterName);
Fariborz Jahanian92f72422013-09-17 19:00:30 +0000956 SetterMethod = D->getInstanceMethod(SetterSelector);
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000957 }
958 }
959 }
Fariborz Jahanian4c3d9c52013-09-17 19:38:55 +0000960
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000961 if (SetterMethod) {
Fariborz Jahanianc1213862013-10-02 21:32:39 +0000962 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
963 return false;
Fariborz Jahanian2ba62a72013-09-18 17:22:25 +0000964 if (SetterMethod->isDeprecated() ||
965 !AttributesMatch(Method, SetterMethod))
Fariborz Jahanianf6c65052013-09-17 22:41:25 +0000966 return false;
Fariborz Jahanian2ba62a72013-09-18 17:22:25 +0000967
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000968 // Is this a valid setter, matching the target getter?
969 QualType SRT = SetterMethod->getResultType();
970 if (!SRT->isVoidType())
971 return false;
972 const ParmVarDecl *argDecl = *SetterMethod->param_begin();
973 QualType ArgType = argDecl->getType();
Fariborz Jahanian2ba62a72013-09-18 17:22:25 +0000974 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000975 return false;
976 edit::Commit commit(*Editor);
977 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
Fariborz Jahanian20a11242013-10-09 19:06:08 +0000978 LengthOfPrefix,
979 (ASTMigrateActions &
980 FrontendOptions::ObjCMT_AtomicProperty) != 0);
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000981 Editor->commit(commit);
982 return true;
983 }
Fariborz Jahanian182486c2013-10-02 17:08:12 +0000984 else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000985 // Try a non-void method with no argument (and no setter or property of same name
986 // as a 'readonly' property.
987 edit::Commit commit(*Editor);
988 rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
Fariborz Jahanian20a11242013-10-09 19:06:08 +0000989 LengthOfPrefix,
990 (ASTMigrateActions &
991 FrontendOptions::ObjCMT_AtomicProperty) != 0);
Fariborz Jahanian215f96c2013-09-06 23:45:20 +0000992 Editor->commit(commit);
993 return true;
994 }
995 return false;
996}
997
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +0000998void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
999 ObjCMethodDecl *OM) {
Fariborz Jahanian10b74352013-09-24 20:20:52 +00001000 if (OM->isImplicit() ||
Fariborz Jahanian7c1a4452013-09-26 22:43:41 +00001001 !OM->isInstanceMethod() ||
Fariborz Jahanian10b74352013-09-24 20:20:52 +00001002 OM->hasAttr<ObjCReturnsInnerPointerAttr>())
Fariborz Jahaniand0fbf6c2013-08-30 23:52:08 +00001003 return;
1004
1005 QualType RT = OM->getResultType();
1006 if (!TypeIsInnerPointer(RT) ||
1007 !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
1008 return;
1009
1010 edit::Commit commit(*Editor);
1011 commit.insertBefore(OM->getLocEnd(), " NS_RETURNS_INNER_POINTER");
1012 Editor->commit(commit);
1013}
1014
Fariborz Jahanian10b74352013-09-24 20:20:52 +00001015void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
1016 ObjCPropertyDecl *P) {
1017 QualType T = P->getType();
1018
1019 if (!TypeIsInnerPointer(T) ||
1020 !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
1021 return;
1022 edit::Commit commit(*Editor);
1023 commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER ");
1024 Editor->commit(commit);
1025}
1026
Fariborz Jahanian8c45e282013-10-02 22:49:59 +00001027void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
Fariborz Jahanian71221352013-07-23 22:42:28 +00001028 ObjCContainerDecl *CDecl) {
Fariborz Jahaniane47a14a2013-09-18 15:43:52 +00001029 if (CDecl->isDeprecated())
1030 return;
1031
Fariborz Jahanian71221352013-07-23 22:42:28 +00001032 // 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 Jahanian75226d52013-09-17 21:56:04 +00001037 if (Method->isDeprecated())
1038 continue;
Fariborz Jahanian71221352013-07-23 22:42:28 +00001039 migrateMethodInstanceType(Ctx, CDecl, Method);
1040 }
1041}
1042
Fariborz Jahanianc4291852013-08-02 18:00:53 +00001043void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
1044 ObjCContainerDecl *CDecl,
Fariborz Jahanian9275c682013-08-02 20:54:18 +00001045 ObjCMethodDecl *OM,
1046 ObjCInstanceTypeFamily OIT_Family) {
Fariborz Jahanian3bfc35e2013-08-02 22:34:18 +00001047 if (OM->isInstanceMethod() ||
1048 OM->getResultType() == Ctx.getObjCInstanceType() ||
1049 !OM->getResultType()->isObjCIdType())
Fariborz Jahanianc4291852013-08-02 18:00:53 +00001050 return;
1051
1052 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
1053 // NSYYYNamE with matching names be at least 3 characters long.
1054 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1055 if (!IDecl) {
1056 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1057 IDecl = CatDecl->getClassInterface();
1058 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1059 IDecl = ImpDecl->getClassInterface();
1060 }
1061 if (!IDecl)
1062 return;
1063
1064 std::string StringClassName = IDecl->getName();
1065 StringRef LoweredClassName(StringClassName);
1066 std::string StringLoweredClassName = LoweredClassName.lower();
1067 LoweredClassName = StringLoweredClassName;
1068
1069 IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +00001070 // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
1071 if (!MethodIdName)
1072 return;
1073
Fariborz Jahanianc4291852013-08-02 18:00:53 +00001074 std::string MethodName = MethodIdName->getName();
Fariborz Jahanian7c87b432013-10-10 18:23:13 +00001075 if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
Fariborz Jahanian9275c682013-08-02 20:54:18 +00001076 StringRef STRefMethodName(MethodName);
1077 size_t len = 0;
1078 if (STRefMethodName.startswith("standard"))
1079 len = strlen("standard");
1080 else if (STRefMethodName.startswith("shared"))
1081 len = strlen("shared");
1082 else if (STRefMethodName.startswith("default"))
1083 len = strlen("default");
1084 else
1085 return;
1086 MethodName = STRefMethodName.substr(len);
1087 }
Fariborz Jahanianc4291852013-08-02 18:00:53 +00001088 std::string MethodNameSubStr = MethodName.substr(0, 3);
1089 StringRef MethodNamePrefix(MethodNameSubStr);
1090 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
1091 MethodNamePrefix = StringLoweredMethodNamePrefix;
1092 size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
1093 if (Ix == StringRef::npos)
1094 return;
1095 std::string ClassNamePostfix = LoweredClassName.substr(Ix);
1096 StringRef LoweredMethodName(MethodName);
1097 std::string StringLoweredMethodName = LoweredMethodName.lower();
1098 LoweredMethodName = StringLoweredMethodName;
1099 if (!LoweredMethodName.startswith(ClassNamePostfix))
1100 return;
Fariborz Jahanian7c87b432013-10-10 18:23:13 +00001101 if (OIT_Family == OIT_ReturnsSelf)
1102 ReplaceWithClasstype(*this, OM);
1103 else
1104 ReplaceWithInstancetype(*this, OM);
Fariborz Jahanianc4291852013-08-02 18:00:53 +00001105}
1106
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +00001107static bool IsVoidStarType(QualType Ty) {
1108 if (!Ty->isPointerType())
1109 return false;
1110
1111 while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
1112 Ty = TD->getDecl()->getUnderlyingType();
1113
1114 // Is the type void*?
1115 const PointerType* PT = Ty->getAs<PointerType>();
1116 if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
1117 return true;
1118 return IsVoidStarType(PT->getPointeeType());
1119}
1120
Fariborz Jahanian94279392013-08-20 18:54:39 +00001121/// AuditedType - This routine audits the type AT and returns false if it is one of known
1122/// CF object types or of the "void *" variety. It returns true if we don't care about the type
1123/// such as a non-pointer or pointers which have no ownership issues (such as "int *").
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001124static bool AuditedType (QualType AT) {
1125 if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001126 return true;
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001127 // FIXME. There isn't much we can say about CF pointer type; or is there?
Fariborz Jahanian94279392013-08-20 18:54:39 +00001128 if (ento::coreFoundation::isCFObjectRef(AT) ||
1129 IsVoidStarType(AT) ||
1130 // If an ObjC object is type, assuming that it is not a CF function and
1131 // that it is an un-audited function.
Fariborz Jahanian2e9c19c2013-08-22 22:27:36 +00001132 AT->isObjCObjectPointerType() || AT->isObjCBuiltinType())
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001133 return false;
Fariborz Jahanian94279392013-08-20 18:54:39 +00001134 // All other pointers are assumed audited as harmless.
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001135 return true;
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +00001136}
1137
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001138void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001139 if (CFFunctionIBCandidates.empty())
1140 return;
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001141 if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) {
1142 CFFunctionIBCandidates.clear();
Fariborz Jahanianb8343522013-08-20 23:35:26 +00001143 FileId = 0;
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001144 return;
1145 }
1146 // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001147 const Decl *FirstFD = CFFunctionIBCandidates[0];
1148 const Decl *LastFD =
1149 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001150 const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
1151 edit::Commit commit(*Editor);
1152 commit.insertBefore(FirstFD->getLocStart(), PragmaString);
1153 PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
1154 SourceLocation EndLoc = LastFD->getLocEnd();
1155 // get location just past end of function location.
1156 EndLoc = PP.getLocForEndOfToken(EndLoc);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001157 if (isa<FunctionDecl>(LastFD)) {
1158 // For Methods, EndLoc points to the ending semcolon. So,
1159 // not of these extra work is needed.
1160 Token Tok;
1161 // get locaiton of token that comes after end of function.
1162 bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
1163 if (!Failed)
1164 EndLoc = Tok.getLocation();
1165 }
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001166 commit.insertAfterToken(EndLoc, PragmaString);
1167 Editor->commit(commit);
Fariborz Jahanianb8343522013-08-20 23:35:26 +00001168 FileId = 0;
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001169 CFFunctionIBCandidates.clear();
1170}
1171
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +00001172void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
Fariborz Jahanian75226d52013-09-17 21:56:04 +00001173 if (Decl->isDeprecated())
1174 return;
1175
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +00001176 if (Decl->hasAttr<CFAuditedTransferAttr>()) {
Fariborz Jahanianc6dfd3f2013-08-19 22:00:50 +00001177 assert(CFFunctionIBCandidates.empty() &&
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +00001178 "Cannot have audited functions/methods inside user "
Fariborz Jahanianc6dfd3f2013-08-19 22:00:50 +00001179 "provided CF_IMPLICIT_BRIDGING_ENABLE");
1180 return;
1181 }
1182
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +00001183 // Finction must be annotated first.
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001184 if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
1185 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
1186 if (AuditKind == CF_BRIDGING_ENABLE) {
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001187 CFFunctionIBCandidates.push_back(Decl);
1188 if (!FileId)
1189 FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue();
1190 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001191 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
1192 if (!CFFunctionIBCandidates.empty()) {
1193 CFFunctionIBCandidates.push_back(Decl);
1194 if (!FileId)
1195 FileId = PP.getSourceManager().getFileID(Decl->getLocation()).getHashValue();
1196 }
1197 }
1198 else
1199 AnnotateImplicitBridging(Ctx);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001200 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001201 else {
1202 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001203 AnnotateImplicitBridging(Ctx);
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001204 }
Fariborz Jahanian2ec4d7b2013-08-16 23:35:05 +00001205}
1206
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001207void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1208 const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001209 const FunctionDecl *FuncDecl,
1210 bool ResultAnnotated) {
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001211 // Annotate function.
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001212 if (!ResultAnnotated) {
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001213 RetEffect Ret = CE.getReturnValue();
1214 const char *AnnotationString = 0;
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001215 if (Ret.getObjKind() == RetEffect::CF) {
1216 if (Ret.isOwned() &&
1217 Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001218 AnnotationString = " CF_RETURNS_RETAINED";
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001219 else if (Ret.notOwned() &&
1220 Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001221 AnnotationString = " CF_RETURNS_NOT_RETAINED";
1222 }
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001223 else if (Ret.getObjKind() == RetEffect::ObjC) {
1224 if (Ret.isOwned() &&
1225 Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
1226 AnnotationString = " NS_RETURNS_RETAINED";
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001227 }
1228
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001229 if (AnnotationString) {
1230 edit::Commit commit(*Editor);
1231 commit.insertAfterToken(FuncDecl->getLocEnd(), AnnotationString);
1232 Editor->commit(commit);
1233 }
Fariborz Jahanian84ac1de2013-08-15 21:44:38 +00001234 }
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001235 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1236 unsigned i = 0;
1237 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1238 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
Fariborz Jahanianb918d7a2013-08-21 19:37:47 +00001239 const ParmVarDecl *pd = *pi;
Fariborz Jahanian9ef4a262013-08-19 19:13:34 +00001240 ArgEffect AE = AEArgs[i];
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001241 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
1242 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
1243 edit::Commit commit(*Editor);
1244 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1245 Editor->commit(commit);
Fariborz Jahanian94279392013-08-20 18:54:39 +00001246 }
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001247 else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() &&
1248 Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) {
1249 edit::Commit commit(*Editor);
1250 commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
1251 Editor->commit(commit);
1252 }
Fariborz Jahanian84ac1de2013-08-15 21:44:38 +00001253 }
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001254}
1255
1256
1257ObjCMigrateASTConsumer::CF_BRIDGING_KIND
1258 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
1259 ASTContext &Ctx,
1260 const FunctionDecl *FuncDecl) {
1261 if (FuncDecl->hasBody())
1262 return CF_BRIDGING_NONE;
1263
1264 CallEffects CE = CallEffects::getEffect(FuncDecl);
1265 bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001266 FuncDecl->getAttr<CFReturnsNotRetainedAttr>() ||
1267 FuncDecl->getAttr<NSReturnsRetainedAttr>() ||
Fariborz Jahanianc24879e2013-09-05 23:04:33 +00001268 FuncDecl->getAttr<NSReturnsNotRetainedAttr>() ||
1269 FuncDecl->getAttr<NSReturnsAutoreleasedAttr>());
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001270
1271 // Trivial case of when funciton is annotated and has no argument.
1272 if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
1273 return CF_BRIDGING_NONE;
1274
1275 bool ReturnCFAudited = false;
1276 if (!FuncIsReturnAnnotated) {
1277 RetEffect Ret = CE.getReturnValue();
1278 if (Ret.getObjKind() == RetEffect::CF &&
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001279 (Ret.isOwned() || Ret.notOwned()))
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001280 ReturnCFAudited = true;
1281 else if (!AuditedType(FuncDecl->getResultType()))
1282 return CF_BRIDGING_NONE;
1283 }
1284
1285 // At this point result type is audited for potential inclusion.
1286 // Now, how about argument types.
1287 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1288 unsigned i = 0;
1289 bool ArgCFAudited = false;
1290 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1291 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1292 const ParmVarDecl *pd = *pi;
1293 ArgEffect AE = AEArgs[i];
1294 if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
1295 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>())
1296 ArgCFAudited = true;
1297 else if (AE == IncRef)
1298 ArgCFAudited = true;
1299 }
1300 else {
1301 QualType AT = pd->getType();
1302 if (!AuditedType(AT)) {
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001303 AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated);
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001304 return CF_BRIDGING_NONE;
1305 }
1306 }
1307 }
1308 if (ReturnCFAudited || ArgCFAudited)
1309 return CF_BRIDGING_ENABLE;
1310
1311 return CF_BRIDGING_MAY_INCLUDE;
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +00001312}
1313
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001314void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
1315 ObjCContainerDecl *CDecl) {
Fariborz Jahanian75226d52013-09-17 21:56:04 +00001316 if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated())
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001317 return;
1318
1319 // migrate methods which can have instancetype as their result type.
1320 for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
1321 MEnd = CDecl->meth_end();
1322 M != MEnd; ++M) {
1323 ObjCMethodDecl *Method = (*M);
Fariborz Jahanian4f64dd22013-08-22 21:40:15 +00001324 migrateCFAnnotation(Ctx, Method);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001325 }
1326}
1327
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001328void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1329 const CallEffects &CE,
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001330 const ObjCMethodDecl *MethodDecl,
1331 bool ResultAnnotated) {
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001332 // Annotate function.
Fariborz Jahanian7ca1d302013-08-27 23:56:54 +00001333 if (!ResultAnnotated) {
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001334 RetEffect Ret = CE.getReturnValue();
1335 const char *AnnotationString = 0;
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001336 if (Ret.getObjKind() == RetEffect::CF) {
1337 if (Ret.isOwned() &&
1338 Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001339 AnnotationString = " CF_RETURNS_RETAINED";
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001340 else if (Ret.notOwned() &&
1341 Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition())
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001342 AnnotationString = " CF_RETURNS_NOT_RETAINED";
1343 }
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001344 else if (Ret.getObjKind() == RetEffect::ObjC) {
Fariborz Jahanianc24879e2013-09-05 23:04:33 +00001345 ObjCMethodFamily OMF = MethodDecl->getMethodFamily();
1346 switch (OMF) {
1347 case clang::OMF_alloc:
1348 case clang::OMF_new:
1349 case clang::OMF_copy:
1350 case clang::OMF_init:
1351 case clang::OMF_mutableCopy:
1352 break;
1353
1354 default:
1355 if (Ret.isOwned() &&
1356 Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition())
1357 AnnotationString = " NS_RETURNS_RETAINED";
Fariborz Jahanianc24879e2013-09-05 23:04:33 +00001358 break;
1359 }
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001360 }
1361
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001362 if (AnnotationString) {
1363 edit::Commit commit(*Editor);
1364 commit.insertBefore(MethodDecl->getLocEnd(), AnnotationString);
1365 Editor->commit(commit);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001366 }
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001367 }
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001368 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1369 unsigned i = 0;
1370 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1371 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1372 const ParmVarDecl *pd = *pi;
1373 ArgEffect AE = AEArgs[i];
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001374 if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
1375 Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
1376 edit::Commit commit(*Editor);
1377 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1378 Editor->commit(commit);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001379 }
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001380 }
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001381}
1382
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001383void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001384 ASTContext &Ctx,
1385 const ObjCMethodDecl *MethodDecl) {
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001386 if (MethodDecl->hasBody() || MethodDecl->isImplicit())
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001387 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001388
1389 CallEffects CE = CallEffects::getEffect(MethodDecl);
1390 bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001391 MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
1392 MethodDecl->getAttr<NSReturnsRetainedAttr>() ||
Fariborz Jahanianc24879e2013-09-05 23:04:33 +00001393 MethodDecl->getAttr<NSReturnsNotRetainedAttr>() ||
1394 MethodDecl->getAttr<NSReturnsAutoreleasedAttr>());
1395
1396 if (CE.getReceiver() == DecRefMsg &&
1397 !MethodDecl->getAttr<NSConsumesSelfAttr>() &&
1398 MethodDecl->getMethodFamily() != OMF_init &&
1399 MethodDecl->getMethodFamily() != OMF_release &&
1400 Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) {
1401 edit::Commit commit(*Editor);
1402 commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF");
1403 Editor->commit(commit);
1404 }
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001405
1406 // Trivial case of when funciton is annotated and has no argument.
1407 if (MethodIsReturnAnnotated &&
1408 (MethodDecl->param_begin() == MethodDecl->param_end()))
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001409 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001410
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001411 if (!MethodIsReturnAnnotated) {
1412 RetEffect Ret = CE.getReturnValue();
Fariborz Jahanian1a269272013-09-04 22:49:19 +00001413 if ((Ret.getObjKind() == RetEffect::CF ||
1414 Ret.getObjKind() == RetEffect::ObjC) &&
1415 (Ret.isOwned() || Ret.notOwned())) {
Fariborz Jahanian8b102302013-09-04 16:43:57 +00001416 AddCFAnnotations(Ctx, CE, MethodDecl, false);
1417 return;
1418 }
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001419 else if (!AuditedType(MethodDecl->getResultType()))
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001420 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001421 }
1422
1423 // At this point result type is either annotated or audited.
1424 // Now, how about argument types.
1425 llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
1426 unsigned i = 0;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001427 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1428 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1429 const ParmVarDecl *pd = *pi;
1430 ArgEffect AE = AEArgs[i];
Fariborz Jahanian8b102302013-09-04 16:43:57 +00001431 if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef ||
1432 !AuditedType(pd->getType())) {
1433 AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
1434 return;
Fariborz Jahanian63ffce22013-08-27 22:42:30 +00001435 }
1436 }
Fariborz Jahanian89f6d102013-09-04 00:10:06 +00001437 return;
Fariborz Jahaniandfe6ed92013-08-12 23:17:13 +00001438}
1439
Ted Kremenekf7639e12012-03-06 20:06:33 +00001440namespace {
1441
1442class RewritesReceiver : public edit::EditsReceiver {
1443 Rewriter &Rewrite;
1444
1445public:
1446 RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
1447
1448 virtual void insert(SourceLocation loc, StringRef text) {
1449 Rewrite.InsertText(loc, text);
1450 }
1451 virtual void replace(CharSourceRange range, StringRef text) {
1452 Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
1453 }
1454};
1455
1456}
1457
Fariborz Jahanian8f5225b2013-10-01 21:16:29 +00001458static bool
1459IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) {
1460 bool Invalid = false;
1461 const SrcMgr::SLocEntry &SEntry =
1462 Ctx.getSourceManager().getSLocEntry(FID, &Invalid);
1463 if (!Invalid && SEntry.isFile()) {
1464 const SrcMgr::FileInfo &FI = SEntry.getFile();
1465 if (!FI.hasLineDirectives()) {
1466 if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem)
1467 return true;
1468 if (FI.getFileCharacteristic() == SrcMgr::C_System) {
1469 // This file is in a system header directory. Continue with commiting change
1470 // only if it is a user specified system directory because user put a
1471 // .system_framework file in the framework directory.
1472 StringRef Directory(file->getDir()->getName());
1473 size_t Ix = Directory.rfind(".framework");
1474 if (Ix == StringRef::npos)
1475 return true;
1476 std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework"));
1477 PatchToSystemFramework += ".system_framework";
1478 if (!llvm::sys::fs::exists(PatchToSystemFramework.data()))
1479 return true;
1480 }
1481 }
1482 }
1483 return false;
1484}
1485
Ted Kremenekf7639e12012-03-06 20:06:33 +00001486void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
Fariborz Jahaniana7437f02013-07-03 23:05:00 +00001487
1488 TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
Fariborz Jahanianc1213862013-10-02 21:32:39 +00001489 if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) {
Fariborz Jahaniand83ef842013-07-09 16:59:14 +00001490 for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
1491 D != DEnd; ++D) {
Fariborz Jahanianb8343522013-08-20 23:35:26 +00001492 if (unsigned FID =
1493 PP.getSourceManager().getFileID((*D)->getLocation()).getHashValue())
Fariborz Jahanian8c45e282013-10-02 22:49:59 +00001494 if (FileId && FileId != FID) {
1495 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1496 AnnotateImplicitBridging(Ctx);
1497 }
1498
Fariborz Jahaniand83ef842013-07-09 16:59:14 +00001499 if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
1500 migrateObjCInterfaceDecl(Ctx, CDecl);
Fariborz Jahanian92f72422013-09-17 19:00:30 +00001501 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D))
1502 migrateObjCInterfaceDecl(Ctx, CatDecl);
Fariborz Jahanian1be01532013-07-12 22:32:19 +00001503 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
1504 ObjCProtocolDecls.insert(PDecl);
1505 else if (const ObjCImplementationDecl *ImpDecl =
Fariborz Jahanian8c45e282013-10-02 22:49:59 +00001506 dyn_cast<ObjCImplementationDecl>(*D)) {
1507 if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance)
1508 migrateProtocolConformance(Ctx, ImpDecl);
1509 }
Fariborz Jahanian92463272013-07-18 20:11:45 +00001510 else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
Fariborz Jahanian059e05e2013-10-15 00:00:28 +00001511 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
1512 continue;
Fariborz Jahanian92463272013-07-18 20:11:45 +00001513 DeclContext::decl_iterator N = D;
Fariborz Jahanian059e05e2013-10-15 00:00:28 +00001514 if (++N != DEnd) {
1515 const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
1516 if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
1517 D++;
1518 }
1519 else
1520 migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0);
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +00001521 }
1522 else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
Fariborz Jahanian059e05e2013-10-15 00:00:28 +00001523 if (ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros) {
1524 DeclContext::decl_iterator N = D;
1525 if (++N != DEnd)
1526 if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
1527 if (migrateNSEnumDecl(Ctx, ED, TD)) {
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +00001528 ++D;
Fariborz Jahanian059e05e2013-10-15 00:00:28 +00001529 continue;
1530 }
Fariborz Jahanian11dd4b12013-10-11 21:34:56 +00001531 }
Fariborz Jahanian059e05e2013-10-15 00:00:28 +00001532 CacheObjCNSIntegerTypedefed(TD);
1533 }
Fariborz Jahanian92463272013-07-18 20:11:45 +00001534 }
Fariborz Jahanian8c45e282013-10-02 22:49:59 +00001535 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
1536 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1537 migrateCFAnnotation(Ctx, FD);
1538 }
Fariborz Jahanianc13c1b02013-08-13 18:01:42 +00001539
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001540 if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
1541 // migrate methods which can have instancetype as their result type.
Fariborz Jahanian8c45e282013-10-02 22:49:59 +00001542 if (ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype)
1543 migrateAllMethodInstaceType(Ctx, CDecl);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001544 // annotate methods with CF annotations.
Fariborz Jahanian8c45e282013-10-02 22:49:59 +00001545 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1546 migrateARCSafeAnnotation(Ctx, CDecl);
Fariborz Jahanian926fafb2013-08-22 18:35:27 +00001547 }
Fariborz Jahaniand83ef842013-07-09 16:59:14 +00001548 }
Fariborz Jahanian8c45e282013-10-02 22:49:59 +00001549 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1550 AnnotateImplicitBridging(Ctx);
Fariborz Jahanian301b5212013-08-20 22:42:13 +00001551 }
Fariborz Jahaniana7437f02013-07-03 23:05:00 +00001552
David Blaikiebbafb8a2012-03-11 07:00:24 +00001553 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
Ted Kremenekf7639e12012-03-06 20:06:33 +00001554 RewritesReceiver Rec(rewriter);
1555 Editor->applyRewrites(Rec);
1556
1557 for (Rewriter::buffer_iterator
1558 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
1559 FileID FID = I->first;
1560 RewriteBuffer &buf = I->second;
1561 const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
1562 assert(file);
Fariborz Jahanian8f5225b2013-10-01 21:16:29 +00001563 if (IsReallyASystemHeader(Ctx, file, FID))
1564 continue;
Dmitri Gribenkof8579502013-01-12 19:30:44 +00001565 SmallString<512> newText;
Ted Kremenekf7639e12012-03-06 20:06:33 +00001566 llvm::raw_svector_ostream vecOS(newText);
1567 buf.write(vecOS);
1568 vecOS.flush();
1569 llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
1570 StringRef(newText.data(), newText.size()), file->getName());
Dmitri Gribenkof8579502013-01-12 19:30:44 +00001571 SmallString<64> filePath(file->getName());
Ted Kremenekf7639e12012-03-06 20:06:33 +00001572 FileMgr.FixupRelativePath(filePath);
1573 Remapper.remap(filePath.str(), memBuf);
1574 }
1575
1576 if (IsOutputFile) {
1577 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
1578 } else {
1579 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
1580 }
1581}
1582
1583bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
Argyrios Kyrtzidisb4822602012-05-24 16:48:23 +00001584 CI.getDiagnostics().setIgnoreAllWarnings(true);
Ted Kremenekf7639e12012-03-06 20:06:33 +00001585 return true;
1586}
1587
1588ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
1589 StringRef InFile) {
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +00001590 PPConditionalDirectiveRecord *
1591 PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
1592 CI.getPreprocessor().addPPCallbacks(PPRec);
Ted Kremenekf7639e12012-03-06 20:06:33 +00001593 return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
Fariborz Jahanianc1213862013-10-02 21:32:39 +00001594 FrontendOptions::ObjCMT_MigrateAll,
Ted Kremenekf7639e12012-03-06 20:06:33 +00001595 Remapper,
1596 CI.getFileManager(),
Argyrios Kyrtzidisf3d587e2012-12-04 07:27:05 +00001597 PPRec,
Fariborz Jahaniana7437f02013-07-03 23:05:00 +00001598 CI.getPreprocessor(),
Ted Kremenekf7639e12012-03-06 20:06:33 +00001599 /*isOutputFile=*/true);
1600}