clang 18.0.0git
ObjCMT.cpp
Go to the documentation of this file.
1//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Transforms.h"
15#include "clang/AST/Attr.h"
16#include "clang/AST/NSAPI.h"
17#include "clang/AST/ParentMap.h"
21#include "clang/Edit/Commit.h"
30#include "llvm/ADT/SmallString.h"
31#include "llvm/ADT/StringSet.h"
32#include "llvm/Support/Path.h"
33#include "llvm/Support/SourceMgr.h"
34#include "llvm/Support/YAMLParser.h"
35
36using namespace clang;
37using namespace arcmt;
38using namespace ento;
39
40namespace {
41
42class ObjCMigrateASTConsumer : public ASTConsumer {
43 enum CF_BRIDGING_KIND {
44 CF_BRIDGING_NONE,
45 CF_BRIDGING_ENABLE,
46 CF_BRIDGING_MAY_INCLUDE
47 };
48
49 void migrateDecl(Decl *D);
50 void migrateObjCContainerDecl(ASTContext &Ctx, ObjCContainerDecl *D);
51 void migrateProtocolConformance(ASTContext &Ctx,
52 const ObjCImplementationDecl *ImpDecl);
53 void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
54 bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
55 const TypedefDecl *TypedefDcl);
56 void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
57 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
58 ObjCMethodDecl *OM);
59 bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
60 void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
61 void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
62 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
64 ObjCInstanceTypeFamily OIT_Family = OIT_None);
65
66 void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
67 void AddCFAnnotations(ASTContext &Ctx,
68 const RetainSummary *RS,
69 const FunctionDecl *FuncDecl, bool ResultAnnotated);
70 void AddCFAnnotations(ASTContext &Ctx,
71 const RetainSummary *RS,
72 const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
73
74 void AnnotateImplicitBridging(ASTContext &Ctx);
75
76 CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
77 const FunctionDecl *FuncDecl);
78
79 void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
80
81 void migrateAddMethodAnnotation(ASTContext &Ctx,
82 const ObjCMethodDecl *MethodDecl);
83
84 void inferDesignatedInitializers(ASTContext &Ctx,
85 const ObjCImplementationDecl *ImplD);
86
87 bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc);
88
89 std::unique_ptr<RetainSummaryManager> Summaries;
90
91public:
92 std::string MigrateDir;
93 unsigned ASTMigrateActions;
94 FileID FileId;
95 const TypedefDecl *NSIntegerTypedefed;
96 const TypedefDecl *NSUIntegerTypedefed;
97 std::unique_ptr<NSAPI> NSAPIObj;
98 std::unique_ptr<edit::EditedSource> Editor;
99 FileRemapper &Remapper;
100 FileManager &FileMgr;
101 const PPConditionalDirectiveRecord *PPRec;
102 Preprocessor &PP;
103 bool IsOutputFile;
104 bool FoundationIncluded;
106 llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
107 llvm::StringSet<> AllowListFilenames;
108
109 RetainSummaryManager &getSummaryManager(ASTContext &Ctx) {
110 if (!Summaries)
111 Summaries.reset(new RetainSummaryManager(Ctx,
112 /*TrackNSCFObjects=*/true,
113 /*trackOSObjects=*/false));
114 return *Summaries;
115 }
116
117 ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions,
118 FileRemapper &remapper, FileManager &fileMgr,
119 const PPConditionalDirectiveRecord *PPRec,
120 Preprocessor &PP, bool isOutputFile,
121 ArrayRef<std::string> AllowList)
122 : MigrateDir(migrateDir), ASTMigrateActions(astMigrateActions),
123 NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
124 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
125 IsOutputFile(isOutputFile), FoundationIncluded(false) {
126 // FIXME: StringSet should have insert(iter, iter) to use here.
127 for (const std::string &Val : AllowList)
128 AllowListFilenames.insert(Val);
129 }
130
131protected:
132 void Initialize(ASTContext &Context) override {
133 NSAPIObj.reset(new NSAPI(Context));
134 Editor.reset(new edit::EditedSource(Context.getSourceManager(),
135 Context.getLangOpts(),
136 PPRec));
137 }
138
139 bool HandleTopLevelDecl(DeclGroupRef DG) override {
140 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
141 migrateDecl(*I);
142 return true;
143 }
144 void HandleInterestingDecl(DeclGroupRef DG) override {
145 // Ignore decls from the PCH.
146 }
148 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
149 }
150
151 void HandleTranslationUnit(ASTContext &Ctx) override;
152
153 bool canModifyFile(StringRef Path) {
154 if (AllowListFilenames.empty())
155 return true;
156 return AllowListFilenames.contains(llvm::sys::path::filename(Path));
157 }
158 bool canModifyFile(OptionalFileEntryRef FE) {
159 if (!FE)
160 return false;
161 return canModifyFile(FE->getName());
162 }
163 bool canModifyFile(FileID FID) {
164 if (FID.isInvalid())
165 return false;
166 return canModifyFile(PP.getSourceManager().getFileEntryRefForID(FID));
167 }
168
169 bool canModify(const Decl *D) {
170 if (!D)
171 return false;
172 if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(D))
173 return canModify(CatImpl->getCategoryDecl());
174 if (const ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D))
175 return canModify(Impl->getClassInterface());
176 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
177 return canModify(cast<Decl>(MD->getDeclContext()));
178
180 return canModifyFile(FID);
181 }
182};
183
184} // end anonymous namespace
185
187 std::unique_ptr<FrontendAction> WrappedAction, StringRef migrateDir,
188 unsigned migrateAction)
189 : WrapperFrontendAction(std::move(WrappedAction)), MigrateDir(migrateDir),
190 ObjCMigAction(migrateAction), CompInst(nullptr) {
191 if (MigrateDir.empty())
192 MigrateDir = "."; // user current directory if none is given.
193}
194
195std::unique_ptr<ASTConsumer>
198 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
199 CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
200 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
201 Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
202 Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
203 MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec,
204 CompInst->getPreprocessor(), false, std::nullopt));
205 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
206}
207
209 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
210 /*ignoreIfFilesChanged=*/true);
211 CompInst = &CI;
213 return true;
214}
215
216namespace {
217 // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp
219 const Expr* Expr = FullExpr->IgnoreImpCasts();
220 return !(isa<ArraySubscriptExpr>(Expr) || isa<CallExpr>(Expr) ||
221 isa<DeclRefExpr>(Expr) || isa<CXXNamedCastExpr>(Expr) ||
222 isa<CXXConstructExpr>(Expr) || isa<CXXThisExpr>(Expr) ||
223 isa<CXXTypeidExpr>(Expr) ||
224 isa<CXXUnresolvedConstructExpr>(Expr) ||
225 isa<ObjCMessageExpr>(Expr) || isa<ObjCPropertyRefExpr>(Expr) ||
226 isa<ObjCProtocolExpr>(Expr) || isa<MemberExpr>(Expr) ||
227 isa<ObjCIvarRefExpr>(Expr) || isa<ParenExpr>(FullExpr) ||
228 isa<ParenListExpr>(Expr) || isa<SizeOfPackExpr>(Expr));
229 }
230
231 /// - Rewrite message expression for Objective-C setter and getters into
232 /// property-dot syntax.
233 bool rewriteToPropertyDotSyntax(const ObjCMessageExpr *Msg,
234 Preprocessor &PP,
235 const NSAPI &NS, edit::Commit &commit,
236 const ParentMap *PMap) {
237 if (!Msg || Msg->isImplicit() ||
240 return false;
241 if (const Expr *Receiver = Msg->getInstanceReceiver())
242 if (Receiver->getType()->isObjCBuiltinType())
243 return false;
244
245 const ObjCMethodDecl *Method = Msg->getMethodDecl();
246 if (!Method)
247 return false;
248 if (!Method->isPropertyAccessor())
249 return false;
250
251 const ObjCPropertyDecl *Prop = Method->findPropertyDecl();
252 if (!Prop)
253 return false;
254
255 SourceRange MsgRange = Msg->getSourceRange();
256 bool ReceiverIsSuper =
258 // for 'super' receiver is nullptr.
259 const Expr *receiver = Msg->getInstanceReceiver();
260 bool NeedsParen =
261 ReceiverIsSuper ? false : subscriptOperatorNeedsParens(receiver);
262 bool IsGetter = (Msg->getNumArgs() == 0);
263 if (IsGetter) {
264 // Find space location range between receiver expression and getter method.
265 SourceLocation BegLoc =
266 ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
267 BegLoc = PP.getLocForEndOfToken(BegLoc);
268 SourceLocation EndLoc = Msg->getSelectorLoc(0);
269 SourceRange SpaceRange(BegLoc, EndLoc);
270 std::string PropertyDotString;
271 // rewrite getter method expression into: receiver.property or
272 // (receiver).property
273 if (NeedsParen) {
274 commit.insertBefore(receiver->getBeginLoc(), "(");
275 PropertyDotString = ").";
276 }
277 else
278 PropertyDotString = ".";
279 PropertyDotString += Prop->getName();
280 commit.replace(SpaceRange, PropertyDotString);
281
282 // remove '[' ']'
283 commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
284 commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
285 } else {
286 if (NeedsParen)
287 commit.insertWrap("(", receiver->getSourceRange(), ")");
288 std::string PropertyDotString = ".";
289 PropertyDotString += Prop->getName();
290 PropertyDotString += " =";
291 const Expr*const* Args = Msg->getArgs();
292 const Expr *RHS = Args[0];
293 if (!RHS)
294 return false;
295 SourceLocation BegLoc =
296 ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
297 BegLoc = PP.getLocForEndOfToken(BegLoc);
298 SourceLocation EndLoc = RHS->getBeginLoc();
299 EndLoc = EndLoc.getLocWithOffset(-1);
300 const char *colon = PP.getSourceManager().getCharacterData(EndLoc);
301 // Add a space after '=' if there is no space between RHS and '='
302 if (colon && colon[0] == ':')
303 PropertyDotString += " ";
304 SourceRange Range(BegLoc, EndLoc);
305 commit.replace(Range, PropertyDotString);
306 // remove '[' ']'
307 commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
308 commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
309 }
310 return true;
311 }
312
313class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
314 ObjCMigrateASTConsumer &Consumer;
315 ParentMap &PMap;
316
317public:
318 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
319 : Consumer(consumer), PMap(PMap) { }
320
321 bool shouldVisitTemplateInstantiations() const { return false; }
322 bool shouldWalkTypesOfTypeLocs() const { return false; }
323
324 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
325 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
326 edit::Commit commit(*Consumer.Editor);
327 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
328 Consumer.Editor->commit(commit);
329 }
330
331 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
332 edit::Commit commit(*Consumer.Editor);
333 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
334 Consumer.Editor->commit(commit);
335 }
336
337 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_PropertyDotSyntax) {
338 edit::Commit commit(*Consumer.Editor);
339 rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
340 commit, &PMap);
341 Consumer.Editor->commit(commit);
342 }
343
344 return true;
345 }
346
347 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
348 // Do depth first; we want to rewrite the subexpressions first so that if
349 // we have to move expressions we will move them already rewritten.
350 for (Stmt *SubStmt : E->children())
351 if (!TraverseStmt(SubStmt))
352 return false;
353
354 return WalkUpFromObjCMessageExpr(E);
355 }
356};
357
358class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
359 ObjCMigrateASTConsumer &Consumer;
360 std::unique_ptr<ParentMap> PMap;
361
362public:
363 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
364
365 bool shouldVisitTemplateInstantiations() const { return false; }
366 bool shouldWalkTypesOfTypeLocs() const { return false; }
367
368 bool TraverseStmt(Stmt *S) {
369 PMap.reset(new ParentMap(S));
370 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
371 return true;
372 }
373};
374} // end anonymous namespace
375
376void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
377 if (!D)
378 return;
379 if (isa<ObjCMethodDecl>(D))
380 return; // Wait for the ObjC container declaration.
381
382 BodyMigrator(*this).TraverseDecl(D);
383}
384
385static void append_attr(std::string &PropertyString, const char *attr,
386 bool &LParenAdded) {
387 if (!LParenAdded) {
388 PropertyString += "(";
389 LParenAdded = true;
390 }
391 else
392 PropertyString += ", ";
393 PropertyString += attr;
394}
395
396static
397void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
398 const std::string& TypeString,
399 const char *name) {
400 const char *argPtr = TypeString.c_str();
401 int paren = 0;
402 while (*argPtr) {
403 switch (*argPtr) {
404 case '(':
405 PropertyString += *argPtr;
406 paren++;
407 break;
408 case ')':
409 PropertyString += *argPtr;
410 paren--;
411 break;
412 case '^':
413 case '*':
414 PropertyString += (*argPtr);
415 if (paren == 1) {
416 PropertyString += name;
417 name = "";
418 }
419 break;
420 default:
421 PropertyString += *argPtr;
422 break;
423 }
424 argPtr++;
425 }
426}
427
428static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
429 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
430 bool RetainableObject = ArgType->isObjCRetainableType();
431 if (RetainableObject &&
432 (propertyLifetime == Qualifiers::OCL_Strong
433 || propertyLifetime == Qualifiers::OCL_None)) {
434 if (const ObjCObjectPointerType *ObjPtrTy =
435 ArgType->getAs<ObjCObjectPointerType>()) {
436 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
437 if (IDecl &&
438 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
439 return "copy";
440 else
441 return "strong";
442 }
443 else if (ArgType->isBlockPointerType())
444 return "copy";
445 } else if (propertyLifetime == Qualifiers::OCL_Weak)
446 // TODO. More precise determination of 'weak' attribute requires
447 // looking into setter's implementation for backing weak ivar.
448 return "weak";
449 else if (RetainableObject)
450 return ArgType->isBlockPointerType() ? "copy" : "strong";
451 return nullptr;
452}
453
454static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
455 const ObjCMethodDecl *Setter,
456 const NSAPI &NS, edit::Commit &commit,
457 unsigned LengthOfPrefix,
458 bool Atomic, bool UseNsIosOnlyMacro,
459 bool AvailabilityArgsMatch) {
460 ASTContext &Context = NS.getASTContext();
461 bool LParenAdded = false;
462 std::string PropertyString = "@property ";
463 if (UseNsIosOnlyMacro && NS.isMacroDefined("NS_NONATOMIC_IOSONLY")) {
464 PropertyString += "(NS_NONATOMIC_IOSONLY";
465 LParenAdded = true;
466 } else if (!Atomic) {
467 PropertyString += "(nonatomic";
468 LParenAdded = true;
469 }
470
471 std::string PropertyNameString = Getter->getNameAsString();
472 StringRef PropertyName(PropertyNameString);
473 if (LengthOfPrefix > 0) {
474 if (!LParenAdded) {
475 PropertyString += "(getter=";
476 LParenAdded = true;
477 }
478 else
479 PropertyString += ", getter=";
480 PropertyString += PropertyNameString;
481 }
482 // Property with no setter may be suggested as a 'readonly' property.
483 if (!Setter)
484 append_attr(PropertyString, "readonly", LParenAdded);
485
486
487 // Short circuit 'delegate' properties that contain the name "delegate" or
488 // "dataSource", or have exact name "target" to have 'assign' attribute.
489 if (PropertyName.equals("target") || PropertyName.contains("delegate") ||
490 PropertyName.contains("dataSource")) {
491 QualType QT = Getter->getReturnType();
492 if (!QT->isRealType())
493 append_attr(PropertyString, "assign", LParenAdded);
494 } else if (!Setter) {
495 QualType ResType = Context.getCanonicalType(Getter->getReturnType());
496 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
497 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
498 } else {
499 const ParmVarDecl *argDecl = *Setter->param_begin();
500 QualType ArgType = Context.getCanonicalType(argDecl->getType());
501 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
502 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
503 }
504 if (LParenAdded)
505 PropertyString += ')';
506 QualType RT = Getter->getReturnType();
507 if (!RT->getAs<TypedefType>()) {
508 // strip off any ARC lifetime qualifier.
509 QualType CanResultTy = Context.getCanonicalType(RT);
510 if (CanResultTy.getQualifiers().hasObjCLifetime()) {
511 Qualifiers Qs = CanResultTy.getQualifiers();
513 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
514 }
515 }
516 PropertyString += " ";
517 PrintingPolicy SubPolicy(Context.getPrintingPolicy());
518 SubPolicy.SuppressStrongLifetime = true;
519 SubPolicy.SuppressLifetimeQualifiers = true;
520 std::string TypeString = RT.getAsString(SubPolicy);
521 if (LengthOfPrefix > 0) {
522 // property name must strip off "is" and lower case the first character
523 // after that; e.g. isContinuous will become continuous.
524 StringRef PropertyNameStringRef(PropertyNameString);
525 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
526 PropertyNameString = std::string(PropertyNameStringRef);
527 bool NoLowering = (isUppercase(PropertyNameString[0]) &&
528 PropertyNameString.size() > 1 &&
529 isUppercase(PropertyNameString[1]));
530 if (!NoLowering)
531 PropertyNameString[0] = toLowercase(PropertyNameString[0]);
532 }
533 if (RT->isBlockPointerType() || RT->isFunctionPointerType())
535 TypeString,
536 PropertyNameString.c_str());
537 else {
538 char LastChar = TypeString[TypeString.size()-1];
539 PropertyString += TypeString;
540 if (LastChar != '*')
541 PropertyString += ' ';
542 PropertyString += PropertyNameString;
543 }
544 SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
545 Selector GetterSelector = Getter->getSelector();
546
547 SourceLocation EndGetterSelectorLoc =
548 StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
550 EndGetterSelectorLoc),
551 PropertyString);
552 if (Setter && AvailabilityArgsMatch) {
553 SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
554 // Get location past ';'
555 EndLoc = EndLoc.getLocWithOffset(1);
556 SourceLocation BeginOfSetterDclLoc = Setter->getBeginLoc();
557 // FIXME. This assumes that setter decl; is immediately preceded by eoln.
558 // It is trying to remove the setter method decl. line entirely.
559 BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
560 commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
561 }
562}
563
565 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D)) {
566 StringRef Name = CatDecl->getName();
567 return Name.endswith("Deprecated");
568 }
569 return false;
570}
571
572void ObjCMigrateASTConsumer::migrateObjCContainerDecl(ASTContext &Ctx,
575 return;
576
577 for (auto *Method : D->methods()) {
578 if (Method->isDeprecated())
579 continue;
580 bool PropertyInferred = migrateProperty(Ctx, D, Method);
581 // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to
582 // the getter method as it ends up on the property itself which we don't want
583 // to do unless -objcmt-returns-innerpointer-property option is on.
584 if (!PropertyInferred ||
586 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
587 migrateNsReturnsInnerPointer(Ctx, Method);
588 }
590 return;
591
592 for (auto *Prop : D->instance_properties()) {
593 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
594 !Prop->isDeprecated())
595 migratePropertyNsReturnsInnerPointer(Ctx, Prop);
596 }
597}
598
599static bool
601 const ObjCImplementationDecl *ImpDecl,
602 const ObjCInterfaceDecl *IDecl,
603 ObjCProtocolDecl *Protocol) {
604 // In auto-synthesis, protocol properties are not synthesized. So,
605 // a conforming protocol must have its required properties declared
606 // in class interface.
607 bool HasAtleastOneRequiredProperty = false;
608 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
609 for (const auto *Property : PDecl->instance_properties()) {
610 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
611 continue;
612 HasAtleastOneRequiredProperty = true;
613 DeclContext::lookup_result R = IDecl->lookup(Property->getDeclName());
614 if (R.empty()) {
615 // Relax the rule and look into class's implementation for a synthesize
616 // or dynamic declaration. Class is implementing a property coming from
617 // another protocol. This still makes the target protocol as conforming.
618 if (!ImpDecl->FindPropertyImplDecl(
619 Property->getDeclName().getAsIdentifierInfo(),
620 Property->getQueryKind()))
621 return false;
622 } else if (auto *ClassProperty = R.find_first<ObjCPropertyDecl>()) {
623 if ((ClassProperty->getPropertyAttributes() !=
624 Property->getPropertyAttributes()) ||
625 !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
626 return false;
627 } else
628 return false;
629 }
630
631 // At this point, all required properties in this protocol conform to those
632 // declared in the class.
633 // Check that class implements the required methods of the protocol too.
634 bool HasAtleastOneRequiredMethod = false;
635 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
636 if (PDecl->meth_begin() == PDecl->meth_end())
637 return HasAtleastOneRequiredProperty;
638 for (const auto *MD : PDecl->methods()) {
639 if (MD->isImplicit())
640 continue;
641 if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
642 continue;
643 DeclContext::lookup_result R = ImpDecl->lookup(MD->getDeclName());
644 if (R.empty())
645 return false;
646 bool match = false;
647 HasAtleastOneRequiredMethod = true;
648 for (NamedDecl *ND : R)
649 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(ND))
650 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
651 match = true;
652 break;
653 }
654 if (!match)
655 return false;
656 }
657 }
658 return HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod;
659}
660
662 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
663 const NSAPI &NS, edit::Commit &commit) {
664 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
665 std::string ClassString;
666 SourceLocation EndLoc =
667 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
668
669 if (Protocols.empty()) {
670 ClassString = '<';
671 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
672 ClassString += ConformingProtocols[i]->getNameAsString();
673 if (i != (e-1))
674 ClassString += ", ";
675 }
676 ClassString += "> ";
677 }
678 else {
679 ClassString = ", ";
680 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
681 ClassString += ConformingProtocols[i]->getNameAsString();
682 if (i != (e-1))
683 ClassString += ", ";
684 }
686 EndLoc = *PL;
687 }
688
689 commit.insertAfterToken(EndLoc, ClassString);
690 return true;
691}
692
693static StringRef GetUnsignedName(StringRef NSIntegerName) {
694 StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName)
695 .Case("int8_t", "uint8_t")
696 .Case("int16_t", "uint16_t")
697 .Case("int32_t", "uint32_t")
698 .Case("NSInteger", "NSUInteger")
699 .Case("int64_t", "uint64_t")
700 .Default(NSIntegerName);
701 return UnsignedName;
702}
703
704static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
705 const TypedefDecl *TypedefDcl,
706 const NSAPI &NS, edit::Commit &commit,
707 StringRef NSIntegerName,
708 bool NSOptions) {
709 std::string ClassString;
710 if (NSOptions) {
711 ClassString = "typedef NS_OPTIONS(";
712 ClassString += GetUnsignedName(NSIntegerName);
713 }
714 else {
715 ClassString = "typedef NS_ENUM(";
716 ClassString += NSIntegerName;
717 }
718 ClassString += ", ";
719
720 ClassString += TypedefDcl->getIdentifier()->getName();
721 ClassString += ')';
722 SourceRange R(EnumDcl->getBeginLoc(), EnumDcl->getBeginLoc());
723 commit.replace(R, ClassString);
724 SourceLocation EndOfEnumDclLoc = EnumDcl->getEndLoc();
725 EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
726 NS.getASTContext(), /*IsDecl*/true);
727 if (EndOfEnumDclLoc.isValid()) {
728 SourceRange EnumDclRange(EnumDcl->getBeginLoc(), EndOfEnumDclLoc);
729 commit.insertFromRange(TypedefDcl->getBeginLoc(), EnumDclRange);
730 }
731 else
732 return false;
733
734 SourceLocation EndTypedefDclLoc = TypedefDcl->getEndLoc();
735 EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
736 NS.getASTContext(), /*IsDecl*/true);
737 if (EndTypedefDclLoc.isValid()) {
738 SourceRange TDRange(TypedefDcl->getBeginLoc(), EndTypedefDclLoc);
739 commit.remove(TDRange);
740 }
741 else
742 return false;
743
744 EndOfEnumDclLoc =
746 /*IsDecl*/ true);
747 if (EndOfEnumDclLoc.isValid()) {
748 SourceLocation BeginOfEnumDclLoc = EnumDcl->getBeginLoc();
749 // FIXME. This assumes that enum decl; is immediately preceded by eoln.
750 // It is trying to remove the enum decl. lines entirely.
751 BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
752 commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
753 return true;
754 }
755 return false;
756}
757
759 const EnumDecl *EnumDcl,
760 const TypedefDecl *TypedefDcl,
761 const NSAPI &NS, edit::Commit &commit,
762 bool IsNSIntegerType) {
763 QualType DesignatedEnumType = EnumDcl->getIntegerType();
764 assert(!DesignatedEnumType.isNull()
765 && "rewriteToNSMacroDecl - underlying enum type is null");
766
767 PrintingPolicy Policy(Ctx.getPrintingPolicy());
768 std::string TypeString = DesignatedEnumType.getAsString(Policy);
769 std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS(";
770 ClassString += TypeString;
771 ClassString += ", ";
772
773 ClassString += TypedefDcl->getIdentifier()->getName();
774 ClassString += ") ";
775 SourceLocation EndLoc = EnumDcl->getBraceRange().getBegin();
776 if (EndLoc.isInvalid())
777 return;
779 CharSourceRange::getCharRange(EnumDcl->getBeginLoc(), EndLoc);
780 commit.replace(R, ClassString);
781 // This is to remove spaces between '}' and typedef name.
782 SourceLocation StartTypedefLoc = EnumDcl->getEndLoc();
783 StartTypedefLoc = StartTypedefLoc.getLocWithOffset(+1);
784 SourceLocation EndTypedefLoc = TypedefDcl->getEndLoc();
785
786 commit.remove(SourceRange(StartTypedefLoc, EndTypedefLoc));
787}
788
790 const EnumDecl *EnumDcl) {
791 bool PowerOfTwo = true;
792 bool AllHexdecimalEnumerator = true;
793 uint64_t MaxPowerOfTwoVal = 0;
794 for (auto *Enumerator : EnumDcl->enumerators()) {
795 const Expr *InitExpr = Enumerator->getInitExpr();
796 if (!InitExpr) {
797 PowerOfTwo = false;
798 AllHexdecimalEnumerator = false;
799 continue;
800 }
801 InitExpr = InitExpr->IgnoreParenCasts();
802 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
803 if (BO->isShiftOp() || BO->isBitwiseOp())
804 return true;
805
806 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
807 if (PowerOfTwo && EnumVal) {
808 if (!llvm::isPowerOf2_64(EnumVal))
809 PowerOfTwo = false;
810 else if (EnumVal > MaxPowerOfTwoVal)
811 MaxPowerOfTwoVal = EnumVal;
812 }
813 if (AllHexdecimalEnumerator && EnumVal) {
814 bool FoundHexdecimalEnumerator = false;
815 SourceLocation EndLoc = Enumerator->getEndLoc();
816 Token Tok;
817 if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
818 if (Tok.isLiteral() && Tok.getLength() > 2) {
819 if (const char *StringLit = Tok.getLiteralData())
820 FoundHexdecimalEnumerator =
821 (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
822 }
823 if (!FoundHexdecimalEnumerator)
824 AllHexdecimalEnumerator = false;
825 }
826 }
827 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
828}
829
830void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
831 const ObjCImplementationDecl *ImpDecl) {
832 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
833 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
834 return;
835 // Find all implicit conforming protocols for this class
836 // and make them explicit.
838 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
839 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
840
841 for (ObjCProtocolDecl *ProtDecl : ObjCProtocolDecls)
842 if (!ExplicitProtocols.count(ProtDecl))
843 PotentialImplicitProtocols.push_back(ProtDecl);
844
845 if (PotentialImplicitProtocols.empty())
846 return;
847
848 // go through list of non-optional methods and properties in each protocol
849 // in the PotentialImplicitProtocols list. If class implements every one of the
850 // methods and properties, then this class conforms to this protocol.
851 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
852 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
853 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
854 PotentialImplicitProtocols[i]))
855 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
856
857 if (ConformingProtocols.empty())
858 return;
859
860 // Further reduce number of conforming protocols. If protocol P1 is in the list
861 // protocol P2 (P2<P1>), No need to include P1.
862 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
863 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
864 bool DropIt = false;
865 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
866 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
867 ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
868 if (PDecl == TargetPDecl)
869 continue;
870 if (PDecl->lookupProtocolNamed(
871 TargetPDecl->getDeclName().getAsIdentifierInfo())) {
872 DropIt = true;
873 break;
874 }
875 }
876 if (!DropIt)
877 MinimalConformingProtocols.push_back(TargetPDecl);
878 }
879 if (MinimalConformingProtocols.empty())
880 return;
881 edit::Commit commit(*Editor);
882 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
883 *NSAPIObj, commit);
884 Editor->commit(commit);
885}
886
887void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
888 const TypedefDecl *TypedefDcl) {
889
890 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
891 if (NSAPIObj->isObjCNSIntegerType(qt))
892 NSIntegerTypedefed = TypedefDcl;
893 else if (NSAPIObj->isObjCNSUIntegerType(qt))
894 NSUIntegerTypedefed = TypedefDcl;
895}
896
897bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
898 const EnumDecl *EnumDcl,
899 const TypedefDecl *TypedefDcl) {
900 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
901 EnumDcl->isDeprecated())
902 return false;
903 if (!TypedefDcl) {
904 if (NSIntegerTypedefed) {
905 TypedefDcl = NSIntegerTypedefed;
906 NSIntegerTypedefed = nullptr;
907 }
908 else if (NSUIntegerTypedefed) {
909 TypedefDcl = NSUIntegerTypedefed;
910 NSUIntegerTypedefed = nullptr;
911 }
912 else
913 return false;
914 FileID FileIdOfTypedefDcl =
915 PP.getSourceManager().getFileID(TypedefDcl->getLocation());
916 FileID FileIdOfEnumDcl =
917 PP.getSourceManager().getFileID(EnumDcl->getLocation());
918 if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
919 return false;
920 }
921 if (TypedefDcl->isDeprecated())
922 return false;
923
924 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
925 StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt);
926
927 if (NSIntegerName.empty()) {
928 // Also check for typedef enum {...} TD;
929 if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
930 if (EnumTy->getDecl() == EnumDcl) {
931 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
932 if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
933 return false;
934 edit::Commit commit(*Editor);
935 rewriteToNSMacroDecl(Ctx, EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
936 Editor->commit(commit);
937 return true;
938 }
939 }
940 return false;
941 }
942
943 // We may still use NS_OPTIONS based on what we find in the enumertor list.
944 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
945 if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
946 return false;
947 edit::Commit commit(*Editor);
948 bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
949 commit, NSIntegerName, NSOptions);
950 Editor->commit(commit);
951 return Res;
952}
953
955 const ObjCMigrateASTConsumer &ASTC,
956 ObjCMethodDecl *OM) {
957 if (OM->getReturnType() == Ctx.getObjCInstanceType())
958 return; // already has instancetype.
959
960 SourceRange R;
961 std::string ClassString;
962 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
963 TypeLoc TL = TSInfo->getTypeLoc();
964 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
965 ClassString = "instancetype";
966 }
967 else {
968 R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
969 ClassString = OM->isInstanceMethod() ? '-' : '+';
970 ClassString += " (instancetype)";
971 }
972 edit::Commit commit(*ASTC.Editor);
973 commit.replace(R, ClassString);
974 ASTC.Editor->commit(commit);
975}
976
977static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
978 ObjCMethodDecl *OM) {
980 SourceRange R;
981 std::string ClassString;
982 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
983 TypeLoc TL = TSInfo->getTypeLoc();
984 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
985 ClassString = std::string(IDecl->getName());
986 ClassString += "*";
987 }
988 }
989 else {
990 R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
991 ClassString = "+ (";
992 ClassString += IDecl->getName(); ClassString += "*)";
993 }
994 edit::Commit commit(*ASTC.Editor);
995 commit.replace(R, ClassString);
996 ASTC.Editor->commit(commit);
997}
998
999void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
1000 ObjCContainerDecl *CDecl,
1001 ObjCMethodDecl *OM) {
1002 ObjCInstanceTypeFamily OIT_Family =
1004
1005 std::string ClassName;
1006 switch (OIT_Family) {
1007 case OIT_None:
1008 migrateFactoryMethod(Ctx, CDecl, OM);
1009 return;
1010 case OIT_Array:
1011 ClassName = "NSArray";
1012 break;
1013 case OIT_Dictionary:
1014 ClassName = "NSDictionary";
1015 break;
1016 case OIT_Singleton:
1017 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
1018 return;
1019 case OIT_Init:
1020 if (OM->getReturnType()->isObjCIdType())
1021 ReplaceWithInstancetype(Ctx, *this, OM);
1022 return;
1023 case OIT_ReturnsSelf:
1024 migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
1025 return;
1026 }
1027 if (!OM->getReturnType()->isObjCIdType())
1028 return;
1029
1030 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1031 if (!IDecl) {
1032 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1033 IDecl = CatDecl->getClassInterface();
1034 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1035 IDecl = ImpDecl->getClassInterface();
1036 }
1037 if (!IDecl ||
1038 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
1039 migrateFactoryMethod(Ctx, CDecl, OM);
1040 return;
1041 }
1042 ReplaceWithInstancetype(Ctx, *this, OM);
1043}
1044
1046 if (!T->isAnyPointerType())
1047 return false;
1048 if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
1051 return false;
1052 // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
1053 // is not an innter pointer type.
1054 QualType OrigT = T;
1055 while (const auto *TD = T->getAs<TypedefType>())
1056 T = TD->getDecl()->getUnderlyingType();
1057 if (OrigT == T || !T->isPointerType())
1058 return true;
1059 const PointerType* PT = T->getAs<PointerType>();
1060 QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
1061 if (UPointeeT->isRecordType()) {
1062 const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
1063 if (!RecordTy->getDecl()->isCompleteDefinition())
1064 return false;
1065 }
1066 return true;
1067}
1068
1069/// Check whether the two versions match.
1070static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) {
1071 return (X == Y);
1072}
1073
1074/// AvailabilityAttrsMatch - This routine checks that if comparing two
1075/// availability attributes, all their components match. It returns
1076/// true, if not dealing with availability or when all components of
1077/// availability attributes match. This routine is only called when
1078/// the attributes are of the same kind.
1079static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
1080 const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
1081 if (!AA1)
1082 return true;
1083 const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2);
1084
1085 VersionTuple Introduced1 = AA1->getIntroduced();
1086 VersionTuple Deprecated1 = AA1->getDeprecated();
1087 VersionTuple Obsoleted1 = AA1->getObsoleted();
1088 bool IsUnavailable1 = AA1->getUnavailable();
1089 VersionTuple Introduced2 = AA2->getIntroduced();
1090 VersionTuple Deprecated2 = AA2->getDeprecated();
1091 VersionTuple Obsoleted2 = AA2->getObsoleted();
1092 bool IsUnavailable2 = AA2->getUnavailable();
1093 return (versionsMatch(Introduced1, Introduced2) &&
1094 versionsMatch(Deprecated1, Deprecated2) &&
1095 versionsMatch(Obsoleted1, Obsoleted2) &&
1096 IsUnavailable1 == IsUnavailable2);
1097}
1098
1099static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2,
1100 bool &AvailabilityArgsMatch) {
1101 // This list is very small, so this need not be optimized.
1102 for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
1103 bool match = false;
1104 for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
1105 // Matching attribute kind only. Except for Availability attributes,
1106 // we are not getting into details of the attributes. For all practical purposes
1107 // this is sufficient.
1108 if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
1109 if (AvailabilityArgsMatch)
1110 AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]);
1111 match = true;
1112 break;
1113 }
1114 }
1115 if (!match)
1116 return false;
1117 }
1118 return true;
1119}
1120
1121/// AttributesMatch - This routine checks list of attributes for two
1122/// decls. It returns false, if there is a mismatch in kind of
1123/// attributes seen in the decls. It returns true if the two decls
1124/// have list of same kind of attributes. Furthermore, when there
1125/// are availability attributes in the two decls, it sets the
1126/// AvailabilityArgsMatch to false if availability attributes have
1127/// different versions, etc.
1128static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2,
1129 bool &AvailabilityArgsMatch) {
1130 if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) {
1131 AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs());
1132 return true;
1133 }
1134 AvailabilityArgsMatch = true;
1135 const AttrVec &Attrs1 = Decl1->getAttrs();
1136 const AttrVec &Attrs2 = Decl2->getAttrs();
1137 bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch);
1138 if (match && (Attrs2.size() > Attrs1.size()))
1139 return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch);
1140 return match;
1141}
1142
1144 const char *Name) {
1145 if (!isAsciiIdentifierStart(Name[0]))
1146 return false;
1147 std::string NameString = Name;
1148 NameString[0] = toLowercase(NameString[0]);
1149 IdentifierInfo *II = &Ctx.Idents.get(NameString);
1150 return II->getTokenID() == tok::identifier;
1151}
1152
1153bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
1155 ObjCMethodDecl *Method) {
1156 if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
1157 Method->param_size() != 0)
1158 return false;
1159 // Is this method candidate to be a getter?
1160 QualType GRT = Method->getReturnType();
1161 if (GRT->isVoidType())
1162 return false;
1163
1164 Selector GetterSelector = Method->getSelector();
1165 ObjCInstanceTypeFamily OIT_Family =
1166 Selector::getInstTypeMethodFamily(GetterSelector);
1167
1168 if (OIT_Family != OIT_None)
1169 return false;
1170
1171 IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
1172 Selector SetterSelector =
1174 PP.getSelectorTable(),
1175 getterName);
1176 ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
1177 unsigned LengthOfPrefix = 0;
1178 if (!SetterMethod) {
1179 // try a different naming convention for getter: isXxxxx
1180 StringRef getterNameString = getterName->getName();
1181 bool IsPrefix = getterNameString.startswith("is");
1182 // Note that we don't want to change an isXXX method of retainable object
1183 // type to property (readonly or otherwise).
1184 if (IsPrefix && GRT->isObjCRetainableType())
1185 return false;
1186 if (IsPrefix || getterNameString.startswith("get")) {
1187 LengthOfPrefix = (IsPrefix ? 2 : 3);
1188 const char *CGetterName = getterNameString.data() + LengthOfPrefix;
1189 // Make sure that first character after "is" or "get" prefix can
1190 // start an identifier.
1191 if (!IsValidIdentifier(Ctx, CGetterName))
1192 return false;
1193 if (CGetterName[0] && isUppercase(CGetterName[0])) {
1194 getterName = &Ctx.Idents.get(CGetterName);
1195 SetterSelector =
1197 PP.getSelectorTable(),
1198 getterName);
1199 SetterMethod = D->getInstanceMethod(SetterSelector);
1200 }
1201 }
1202 }
1203
1204 if (SetterMethod) {
1205 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
1206 return false;
1207 bool AvailabilityArgsMatch;
1208 if (SetterMethod->isDeprecated() ||
1209 !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch))
1210 return false;
1211
1212 // Is this a valid setter, matching the target getter?
1213 QualType SRT = SetterMethod->getReturnType();
1214 if (!SRT->isVoidType())
1215 return false;
1216 const ParmVarDecl *argDecl = *SetterMethod->param_begin();
1217 QualType ArgType = argDecl->getType();
1218 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
1219 return false;
1220 edit::Commit commit(*Editor);
1221 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
1222 LengthOfPrefix,
1223 (ASTMigrateActions &
1225 (ASTMigrateActions &
1227 AvailabilityArgsMatch);
1228 Editor->commit(commit);
1229 return true;
1230 }
1231 else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
1232 // Try a non-void method with no argument (and no setter or property of same name
1233 // as a 'readonly' property.
1234 edit::Commit commit(*Editor);
1235 rewriteToObjCProperty(Method, nullptr /*SetterMethod*/, *NSAPIObj, commit,
1236 LengthOfPrefix,
1237 (ASTMigrateActions &
1239 (ASTMigrateActions &
1241 /*AvailabilityArgsMatch*/false);
1242 Editor->commit(commit);
1243 return true;
1244 }
1245 return false;
1246}
1247
1248void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
1249 ObjCMethodDecl *OM) {
1250 if (OM->isImplicit() ||
1251 !OM->isInstanceMethod() ||
1252 OM->hasAttr<ObjCReturnsInnerPointerAttr>())
1253 return;
1254
1255 QualType RT = OM->getReturnType();
1256 if (!TypeIsInnerPointer(RT) ||
1257 !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
1258 return;
1259
1260 edit::Commit commit(*Editor);
1261 commit.insertBefore(OM->getEndLoc(), " NS_RETURNS_INNER_POINTER");
1262 Editor->commit(commit);
1263}
1264
1265void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
1267 QualType T = P->getType();
1268
1269 if (!TypeIsInnerPointer(T) ||
1270 !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
1271 return;
1272 edit::Commit commit(*Editor);
1273 commit.insertBefore(P->getEndLoc(), " NS_RETURNS_INNER_POINTER ");
1274 Editor->commit(commit);
1275}
1276
1277void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
1278 ObjCContainerDecl *CDecl) {
1279 if (CDecl->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(CDecl))
1280 return;
1281
1282 // migrate methods which can have instancetype as their result type.
1283 for (auto *Method : CDecl->methods()) {
1284 if (Method->isDeprecated())
1285 continue;
1286 migrateMethodInstanceType(Ctx, CDecl, Method);
1287 }
1288}
1289
1290void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
1291 ObjCContainerDecl *CDecl,
1292 ObjCMethodDecl *OM,
1293 ObjCInstanceTypeFamily OIT_Family) {
1294 if (OM->isInstanceMethod() ||
1295 OM->getReturnType() == Ctx.getObjCInstanceType() ||
1296 !OM->getReturnType()->isObjCIdType())
1297 return;
1298
1299 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
1300 // NSYYYNamE with matching names be at least 3 characters long.
1301 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1302 if (!IDecl) {
1303 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1304 IDecl = CatDecl->getClassInterface();
1305 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1306 IDecl = ImpDecl->getClassInterface();
1307 }
1308 if (!IDecl)
1309 return;
1310
1311 std::string StringClassName = std::string(IDecl->getName());
1312 StringRef LoweredClassName(StringClassName);
1313 std::string StringLoweredClassName = LoweredClassName.lower();
1314 LoweredClassName = StringLoweredClassName;
1315
1316 IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
1317 // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
1318 if (!MethodIdName)
1319 return;
1320
1321 std::string MethodName = std::string(MethodIdName->getName());
1322 if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
1323 StringRef STRefMethodName(MethodName);
1324 size_t len = 0;
1325 if (STRefMethodName.startswith("standard"))
1326 len = strlen("standard");
1327 else if (STRefMethodName.startswith("shared"))
1328 len = strlen("shared");
1329 else if (STRefMethodName.startswith("default"))
1330 len = strlen("default");
1331 else
1332 return;
1333 MethodName = std::string(STRefMethodName.substr(len));
1334 }
1335 std::string MethodNameSubStr = MethodName.substr(0, 3);
1336 StringRef MethodNamePrefix(MethodNameSubStr);
1337 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
1338 MethodNamePrefix = StringLoweredMethodNamePrefix;
1339 size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
1340 if (Ix == StringRef::npos)
1341 return;
1342 std::string ClassNamePostfix = std::string(LoweredClassName.substr(Ix));
1343 StringRef LoweredMethodName(MethodName);
1344 std::string StringLoweredMethodName = LoweredMethodName.lower();
1345 LoweredMethodName = StringLoweredMethodName;
1346 if (!LoweredMethodName.startswith(ClassNamePostfix))
1347 return;
1348 if (OIT_Family == OIT_ReturnsSelf)
1349 ReplaceWithClasstype(*this, OM);
1350 else
1351 ReplaceWithInstancetype(Ctx, *this, OM);
1352}
1353
1354static bool IsVoidStarType(QualType Ty) {
1355 if (!Ty->isPointerType())
1356 return false;
1357
1358 // Is the type void*?
1359 const PointerType* PT = Ty->castAs<PointerType>();
1361 return true;
1362 return IsVoidStarType(PT->getPointeeType());
1363}
1364
1365/// AuditedType - This routine audits the type AT and returns false if it is one of known
1366/// CF object types or of the "void *" variety. It returns true if we don't care about the type
1367/// such as a non-pointer or pointers which have no ownership issues (such as "int *").
1368static bool AuditedType (QualType AT) {
1369 if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
1370 return true;
1371 // FIXME. There isn't much we can say about CF pointer type; or is there?
1373 IsVoidStarType(AT) ||
1374 // If an ObjC object is type, assuming that it is not a CF function and
1375 // that it is an un-audited function.
1377 return false;
1378 // All other pointers are assumed audited as harmless.
1379 return true;
1380}
1381
1382void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
1383 if (CFFunctionIBCandidates.empty())
1384 return;
1385 if (!NSAPIObj->isMacroDefined("CF_IMPLICIT_BRIDGING_ENABLED")) {
1386 CFFunctionIBCandidates.clear();
1387 FileId = FileID();
1388 return;
1389 }
1390 // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
1391 const Decl *FirstFD = CFFunctionIBCandidates[0];
1392 const Decl *LastFD =
1393 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
1394 const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
1395 edit::Commit commit(*Editor);
1396 commit.insertBefore(FirstFD->getBeginLoc(), PragmaString);
1397 PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
1398 SourceLocation EndLoc = LastFD->getEndLoc();
1399 // get location just past end of function location.
1400 EndLoc = PP.getLocForEndOfToken(EndLoc);
1401 if (isa<FunctionDecl>(LastFD)) {
1402 // For Methods, EndLoc points to the ending semcolon. So,
1403 // not of these extra work is needed.
1404 Token Tok;
1405 // get locaiton of token that comes after end of function.
1406 bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
1407 if (!Failed)
1408 EndLoc = Tok.getLocation();
1409 }
1410 commit.insertAfterToken(EndLoc, PragmaString);
1411 Editor->commit(commit);
1412 FileId = FileID();
1413 CFFunctionIBCandidates.clear();
1414}
1415
1416void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
1417 if (Decl->isDeprecated())
1418 return;
1419
1420 if (Decl->hasAttr<CFAuditedTransferAttr>()) {
1421 assert(CFFunctionIBCandidates.empty() &&
1422 "Cannot have audited functions/methods inside user "
1423 "provided CF_IMPLICIT_BRIDGING_ENABLE");
1424 return;
1425 }
1426
1427 // Finction must be annotated first.
1428 if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
1429 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
1430 if (AuditKind == CF_BRIDGING_ENABLE) {
1431 CFFunctionIBCandidates.push_back(Decl);
1432 if (FileId.isInvalid())
1433 FileId = PP.getSourceManager().getFileID(Decl->getLocation());
1434 }
1435 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
1436 if (!CFFunctionIBCandidates.empty()) {
1437 CFFunctionIBCandidates.push_back(Decl);
1438 if (FileId.isInvalid())
1439 FileId = PP.getSourceManager().getFileID(Decl->getLocation());
1440 }
1441 }
1442 else
1443 AnnotateImplicitBridging(Ctx);
1444 }
1445 else {
1446 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
1447 AnnotateImplicitBridging(Ctx);
1448 }
1449}
1450
1451void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1452 const RetainSummary *RS,
1453 const FunctionDecl *FuncDecl,
1454 bool ResultAnnotated) {
1455 // Annotate function.
1456 if (!ResultAnnotated) {
1457 RetEffect Ret = RS->getRetEffect();
1458 const char *AnnotationString = nullptr;
1459 if (Ret.getObjKind() == ObjKind::CF) {
1460 if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
1461 AnnotationString = " CF_RETURNS_RETAINED";
1462 else if (Ret.notOwned() &&
1463 NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED"))
1464 AnnotationString = " CF_RETURNS_NOT_RETAINED";
1465 }
1466 else if (Ret.getObjKind() == ObjKind::ObjC) {
1467 if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED"))
1468 AnnotationString = " NS_RETURNS_RETAINED";
1469 }
1470
1471 if (AnnotationString) {
1472 edit::Commit commit(*Editor);
1473 commit.insertAfterToken(FuncDecl->getEndLoc(), AnnotationString);
1474 Editor->commit(commit);
1475 }
1476 }
1477 unsigned i = 0;
1478 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1479 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1480 const ParmVarDecl *pd = *pi;
1481 ArgEffect AE = RS->getArg(i);
1482 if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF &&
1483 !pd->hasAttr<CFConsumedAttr>() &&
1484 NSAPIObj->isMacroDefined("CF_CONSUMED")) {
1485 edit::Commit commit(*Editor);
1486 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1487 Editor->commit(commit);
1488 } else if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::ObjC &&
1489 !pd->hasAttr<NSConsumedAttr>() &&
1490 NSAPIObj->isMacroDefined("NS_CONSUMED")) {
1491 edit::Commit commit(*Editor);
1492 commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
1493 Editor->commit(commit);
1494 }
1495 }
1496}
1497
1498ObjCMigrateASTConsumer::CF_BRIDGING_KIND
1499 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
1500 ASTContext &Ctx,
1501 const FunctionDecl *FuncDecl) {
1502 if (FuncDecl->hasBody())
1503 return CF_BRIDGING_NONE;
1504
1505 const RetainSummary *RS =
1506 getSummaryManager(Ctx).getSummary(AnyCall(FuncDecl));
1507 bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() ||
1508 FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
1509 FuncDecl->hasAttr<NSReturnsRetainedAttr>() ||
1510 FuncDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
1511 FuncDecl->hasAttr<NSReturnsAutoreleasedAttr>());
1512
1513 // Trivial case of when function is annotated and has no argument.
1514 if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
1515 return CF_BRIDGING_NONE;
1516
1517 bool ReturnCFAudited = false;
1518 if (!FuncIsReturnAnnotated) {
1519 RetEffect Ret = RS->getRetEffect();
1520 if (Ret.getObjKind() == ObjKind::CF &&
1521 (Ret.isOwned() || Ret.notOwned()))
1522 ReturnCFAudited = true;
1523 else if (!AuditedType(FuncDecl->getReturnType()))
1524 return CF_BRIDGING_NONE;
1525 }
1526
1527 // At this point result type is audited for potential inclusion.
1528 unsigned i = 0;
1529 bool ArgCFAudited = false;
1530 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1531 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1532 const ParmVarDecl *pd = *pi;
1533 ArgEffect AE = RS->getArg(i);
1534 if ((AE.getKind() == DecRef /*CFConsumed annotated*/ ||
1535 AE.getKind() == IncRef) && AE.getObjKind() == ObjKind::CF) {
1536 if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>())
1537 ArgCFAudited = true;
1538 else if (AE.getKind() == IncRef)
1539 ArgCFAudited = true;
1540 } else {
1541 QualType AT = pd->getType();
1542 if (!AuditedType(AT)) {
1543 AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated);
1544 return CF_BRIDGING_NONE;
1545 }
1546 }
1547 }
1548 if (ReturnCFAudited || ArgCFAudited)
1549 return CF_BRIDGING_ENABLE;
1550
1551 return CF_BRIDGING_MAY_INCLUDE;
1552}
1553
1554void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
1555 ObjCContainerDecl *CDecl) {
1556 if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated())
1557 return;
1558
1559 // migrate methods which can have instancetype as their result type.
1560 for (const auto *Method : CDecl->methods())
1561 migrateCFAnnotation(Ctx, Method);
1562}
1563
1564void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1565 const RetainSummary *RS,
1566 const ObjCMethodDecl *MethodDecl,
1567 bool ResultAnnotated) {
1568 // Annotate function.
1569 if (!ResultAnnotated) {
1570 RetEffect Ret = RS->getRetEffect();
1571 const char *AnnotationString = nullptr;
1572 if (Ret.getObjKind() == ObjKind::CF) {
1573 if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
1574 AnnotationString = " CF_RETURNS_RETAINED";
1575 else if (Ret.notOwned() &&
1576 NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED"))
1577 AnnotationString = " CF_RETURNS_NOT_RETAINED";
1578 }
1579 else if (Ret.getObjKind() == ObjKind::ObjC) {
1580 ObjCMethodFamily OMF = MethodDecl->getMethodFamily();
1581 switch (OMF) {
1582 case clang::OMF_alloc:
1583 case clang::OMF_new:
1584 case clang::OMF_copy:
1585 case clang::OMF_init:
1587 break;
1588
1589 default:
1590 if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED"))
1591 AnnotationString = " NS_RETURNS_RETAINED";
1592 break;
1593 }
1594 }
1595
1596 if (AnnotationString) {
1597 edit::Commit commit(*Editor);
1598 commit.insertBefore(MethodDecl->getEndLoc(), AnnotationString);
1599 Editor->commit(commit);
1600 }
1601 }
1602 unsigned i = 0;
1603 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1604 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1605 const ParmVarDecl *pd = *pi;
1606 ArgEffect AE = RS->getArg(i);
1607 if (AE.getKind() == DecRef
1608 && AE.getObjKind() == ObjKind::CF
1609 && !pd->hasAttr<CFConsumedAttr>() &&
1610 NSAPIObj->isMacroDefined("CF_CONSUMED")) {
1611 edit::Commit commit(*Editor);
1612 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1613 Editor->commit(commit);
1614 }
1615 }
1616}
1617
1618void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
1619 ASTContext &Ctx,
1620 const ObjCMethodDecl *MethodDecl) {
1621 if (MethodDecl->hasBody() || MethodDecl->isImplicit())
1622 return;
1623
1624 const RetainSummary *RS =
1625 getSummaryManager(Ctx).getSummary(AnyCall(MethodDecl));
1626
1627 bool MethodIsReturnAnnotated =
1628 (MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
1629 MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
1630 MethodDecl->hasAttr<NSReturnsRetainedAttr>() ||
1631 MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
1632 MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
1633
1634 if (RS->getReceiverEffect().getKind() == DecRef &&
1635 !MethodDecl->hasAttr<NSConsumesSelfAttr>() &&
1636 MethodDecl->getMethodFamily() != OMF_init &&
1637 MethodDecl->getMethodFamily() != OMF_release &&
1638 NSAPIObj->isMacroDefined("NS_CONSUMES_SELF")) {
1639 edit::Commit commit(*Editor);
1640 commit.insertBefore(MethodDecl->getEndLoc(), " NS_CONSUMES_SELF");
1641 Editor->commit(commit);
1642 }
1643
1644 // Trivial case of when function is annotated and has no argument.
1645 if (MethodIsReturnAnnotated &&
1646 (MethodDecl->param_begin() == MethodDecl->param_end()))
1647 return;
1648
1649 if (!MethodIsReturnAnnotated) {
1650 RetEffect Ret = RS->getRetEffect();
1651 if ((Ret.getObjKind() == ObjKind::CF ||
1652 Ret.getObjKind() == ObjKind::ObjC) &&
1653 (Ret.isOwned() || Ret.notOwned())) {
1654 AddCFAnnotations(Ctx, RS, MethodDecl, false);
1655 return;
1656 } else if (!AuditedType(MethodDecl->getReturnType()))
1657 return;
1658 }
1659
1660 // At this point result type is either annotated or audited.
1661 unsigned i = 0;
1662 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1663 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1664 const ParmVarDecl *pd = *pi;
1665 ArgEffect AE = RS->getArg(i);
1666 if ((AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) ||
1667 AE.getKind() == IncRef || !AuditedType(pd->getType())) {
1668 AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated);
1669 return;
1670 }
1671 }
1672}
1673
1674namespace {
1675class SuperInitChecker : public RecursiveASTVisitor<SuperInitChecker> {
1676public:
1677 bool shouldVisitTemplateInstantiations() const { return false; }
1678 bool shouldWalkTypesOfTypeLocs() const { return false; }
1679
1680 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
1682 if (E->getMethodFamily() == OMF_init)
1683 return false;
1684 }
1685 return true;
1686 }
1687};
1688} // end anonymous namespace
1689
1690static bool hasSuperInitCall(const ObjCMethodDecl *MD) {
1691 return !SuperInitChecker().TraverseStmt(MD->getBody());
1692}
1693
1694void ObjCMigrateASTConsumer::inferDesignatedInitializers(
1695 ASTContext &Ctx,
1696 const ObjCImplementationDecl *ImplD) {
1697
1698 const ObjCInterfaceDecl *IFace = ImplD->getClassInterface();
1699 if (!IFace || IFace->hasDesignatedInitializers())
1700 return;
1701 if (!NSAPIObj->isMacroDefined("NS_DESIGNATED_INITIALIZER"))
1702 return;
1703
1704 for (const auto *MD : ImplD->instance_methods()) {
1705 if (MD->isDeprecated() ||
1706 MD->getMethodFamily() != OMF_init ||
1707 MD->isDesignatedInitializerForTheInterface())
1708 continue;
1709 const ObjCMethodDecl *IFaceM = IFace->getMethod(MD->getSelector(),
1710 /*isInstance=*/true);
1711 if (!IFaceM)
1712 continue;
1713 if (hasSuperInitCall(MD)) {
1714 edit::Commit commit(*Editor);
1715 commit.insert(IFaceM->getEndLoc(), " NS_DESIGNATED_INITIALIZER");
1716 Editor->commit(commit);
1717 }
1718 }
1719}
1720
1721bool ObjCMigrateASTConsumer::InsertFoundation(ASTContext &Ctx,
1723 if (FoundationIncluded)
1724 return true;
1725 if (Loc.isInvalid())
1726 return false;
1727 auto *nsEnumId = &Ctx.Idents.get("NS_ENUM");
1728 if (PP.getMacroDefinitionAtLoc(nsEnumId, Loc)) {
1729 FoundationIncluded = true;
1730 return true;
1731 }
1732 edit::Commit commit(*Editor);
1733 if (Ctx.getLangOpts().Modules)
1734 commit.insert(Loc, "#ifndef NS_ENUM\n@import Foundation;\n#endif\n");
1735 else
1736 commit.insert(Loc, "#ifndef NS_ENUM\n#import <Foundation/Foundation.h>\n#endif\n");
1737 Editor->commit(commit);
1738 FoundationIncluded = true;
1739 return true;
1740}
1741
1742namespace {
1743
1744class RewritesReceiver : public edit::EditsReceiver {
1746
1747public:
1748 RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
1749
1750 void insert(SourceLocation loc, StringRef text) override {
1751 Rewrite.InsertText(loc, text);
1752 }
1753 void replace(CharSourceRange range, StringRef text) override {
1754 Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
1755 }
1756};
1757
1758class JSONEditWriter : public edit::EditsReceiver {
1759 SourceManager &SourceMgr;
1760 llvm::raw_ostream &OS;
1761
1762public:
1763 JSONEditWriter(SourceManager &SM, llvm::raw_ostream &OS)
1764 : SourceMgr(SM), OS(OS) {
1765 OS << "[\n";
1766 }
1767 ~JSONEditWriter() override { OS << "]\n"; }
1768
1769private:
1770 struct EntryWriter {
1771 SourceManager &SourceMgr;
1772 llvm::raw_ostream &OS;
1773
1774 EntryWriter(SourceManager &SM, llvm::raw_ostream &OS)
1775 : SourceMgr(SM), OS(OS) {
1776 OS << " {\n";
1777 }
1778 ~EntryWriter() {
1779 OS << " },\n";
1780 }
1781
1782 void writeLoc(SourceLocation Loc) {
1783 FileID FID;
1784 unsigned Offset;
1785 std::tie(FID, Offset) = SourceMgr.getDecomposedLoc(Loc);
1786 assert(FID.isValid());
1787 SmallString<200> Path =
1788 StringRef(SourceMgr.getFileEntryRefForID(FID)->getName());
1789 llvm::sys::fs::make_absolute(Path);
1790 OS << " \"file\": \"";
1791 OS.write_escaped(Path.str()) << "\",\n";
1792 OS << " \"offset\": " << Offset << ",\n";
1793 }
1794
1795 void writeRemove(CharSourceRange Range) {
1796 assert(Range.isCharRange());
1797 std::pair<FileID, unsigned> Begin =
1798 SourceMgr.getDecomposedLoc(Range.getBegin());
1799 std::pair<FileID, unsigned> End =
1800 SourceMgr.getDecomposedLoc(Range.getEnd());
1801 assert(Begin.first == End.first);
1802 assert(Begin.second <= End.second);
1803 unsigned Length = End.second - Begin.second;
1804
1805 OS << " \"remove\": " << Length << ",\n";
1806 }
1807
1808 void writeText(StringRef Text) {
1809 OS << " \"text\": \"";
1810 OS.write_escaped(Text) << "\",\n";
1811 }
1812 };
1813
1814 void insert(SourceLocation Loc, StringRef Text) override {
1815 EntryWriter Writer(SourceMgr, OS);
1816 Writer.writeLoc(Loc);
1817 Writer.writeText(Text);
1818 }
1819
1820 void replace(CharSourceRange Range, StringRef Text) override {
1821 EntryWriter Writer(SourceMgr, OS);
1822 Writer.writeLoc(Range.getBegin());
1823 Writer.writeRemove(Range);
1824 Writer.writeText(Text);
1825 }
1826
1827 void remove(CharSourceRange Range) override {
1828 EntryWriter Writer(SourceMgr, OS);
1829 Writer.writeLoc(Range.getBegin());
1830 Writer.writeRemove(Range);
1831 }
1832};
1833
1834} // end anonymous namespace
1835
1836void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
1837
1839 if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) {
1840 for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
1841 D != DEnd; ++D) {
1842 FileID FID = PP.getSourceManager().getFileID((*D)->getLocation());
1843 if (FID.isValid())
1844 if (FileId.isValid() && FileId != FID) {
1845 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1846 AnnotateImplicitBridging(Ctx);
1847 }
1848
1849 if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
1850 if (canModify(CDecl))
1851 migrateObjCContainerDecl(Ctx, CDecl);
1852 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
1853 if (canModify(CatDecl))
1854 migrateObjCContainerDecl(Ctx, CatDecl);
1855 }
1856 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) {
1857 ObjCProtocolDecls.insert(PDecl->getCanonicalDecl());
1858 if (canModify(PDecl))
1859 migrateObjCContainerDecl(Ctx, PDecl);
1860 }
1861 else if (const ObjCImplementationDecl *ImpDecl =
1862 dyn_cast<ObjCImplementationDecl>(*D)) {
1863 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) &&
1864 canModify(ImpDecl))
1865 migrateProtocolConformance(Ctx, ImpDecl);
1866 }
1867 else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
1868 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
1869 continue;
1870 if (!canModify(ED))
1871 continue;
1873 if (++N != DEnd) {
1874 const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
1875 if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
1876 D++;
1877 }
1878 else
1879 migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */nullptr);
1880 }
1881 else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
1882 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
1883 continue;
1884 if (!canModify(TD))
1885 continue;
1887 if (++N == DEnd)
1888 continue;
1889 if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
1890 if (canModify(ED)) {
1891 if (++N != DEnd)
1892 if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
1893 // prefer typedef-follows-enum to enum-follows-typedef pattern.
1894 if (migrateNSEnumDecl(Ctx, ED, TDF)) {
1895 ++D; ++D;
1896 CacheObjCNSIntegerTypedefed(TD);
1897 continue;
1898 }
1899 }
1900 if (migrateNSEnumDecl(Ctx, ED, TD)) {
1901 ++D;
1902 continue;
1903 }
1904 }
1905 }
1906 CacheObjCNSIntegerTypedefed(TD);
1907 }
1908 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
1909 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
1910 canModify(FD))
1911 migrateCFAnnotation(Ctx, FD);
1912 }
1913
1914 if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
1915 bool CanModify = canModify(CDecl);
1916 // migrate methods which can have instancetype as their result type.
1917 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) &&
1918 CanModify)
1919 migrateAllMethodInstaceType(Ctx, CDecl);
1920 // annotate methods with CF annotations.
1921 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
1922 CanModify)
1923 migrateARCSafeAnnotation(Ctx, CDecl);
1924 }
1925
1926 if (const ObjCImplementationDecl *
1927 ImplD = dyn_cast<ObjCImplementationDecl>(*D)) {
1928 if ((ASTMigrateActions & FrontendOptions::ObjCMT_DesignatedInitializer) &&
1929 canModify(ImplD))
1930 inferDesignatedInitializers(Ctx, ImplD);
1931 }
1932 }
1933 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1934 AnnotateImplicitBridging(Ctx);
1935 }
1936
1937 if (IsOutputFile) {
1938 std::error_code EC;
1939 llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::OF_None);
1940 if (EC) {
1941 DiagnosticsEngine &Diags = Ctx.getDiagnostics();
1943 << EC.message();
1944 return;
1945 }
1946
1947 JSONEditWriter Writer(Ctx.getSourceManager(), OS);
1948 Editor->applyRewrites(Writer);
1949 return;
1950 }
1951
1952 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
1953 RewritesReceiver Rec(rewriter);
1954 Editor->applyRewrites(Rec);
1955
1957 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
1958 FileID FID = I->first;
1959 RewriteBuffer &buf = I->second;
1962 assert(file);
1963 SmallString<512> newText;
1964 llvm::raw_svector_ostream vecOS(newText);
1965 buf.write(vecOS);
1966 std::unique_ptr<llvm::MemoryBuffer> memBuf(
1967 llvm::MemoryBuffer::getMemBufferCopy(
1968 StringRef(newText.data(), newText.size()), file->getName()));
1969 SmallString<64> filePath(file->getName());
1970 FileMgr.FixupRelativePath(filePath);
1971 Remapper.remap(filePath.str(), std::move(memBuf));
1972 }
1973
1974 if (IsOutputFile) {
1975 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
1976 } else {
1977 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
1978 }
1979}
1980
1983 return true;
1984}
1985
1986static std::vector<std::string> getAllowListFilenames(StringRef DirPath) {
1987 using namespace llvm::sys::fs;
1988 using namespace llvm::sys::path;
1989
1990 std::vector<std::string> Filenames;
1991 if (DirPath.empty() || !is_directory(DirPath))
1992 return Filenames;
1993
1994 std::error_code EC;
1995 directory_iterator DI = directory_iterator(DirPath, EC);
1996 directory_iterator DE;
1997 for (; !EC && DI != DE; DI = DI.increment(EC)) {
1998 if (is_regular_file(DI->path()))
1999 Filenames.push_back(std::string(filename(DI->path())));
2000 }
2001
2002 return Filenames;
2003}
2004
2005std::unique_ptr<ASTConsumer>
2009 unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
2010 unsigned ObjCMTOpts = ObjCMTAction;
2011 // These are companion flags, they do not enable transformations.
2014 if (ObjCMTOpts == FrontendOptions::ObjCMT_None) {
2015 // If no specific option was given, enable literals+subscripting transforms
2016 // by default.
2017 ObjCMTAction |=
2019 }
2020 CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
2021 std::vector<std::string> AllowList =
2023 return std::make_unique<ObjCMigrateASTConsumer>(
2024 CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper,
2025 CI.getFileManager(), PPRec, CI.getPreprocessor(),
2026 /*isOutputFile=*/true, AllowList);
2027}
2028
2029namespace {
2030struct EditEntry {
2032 unsigned Offset = 0;
2033 unsigned RemoveLen = 0;
2034 std::string Text;
2035};
2036} // end anonymous namespace
2037
2038namespace llvm {
2039template<> struct DenseMapInfo<EditEntry> {
2040 static inline EditEntry getEmptyKey() {
2041 EditEntry Entry;
2042 Entry.Offset = unsigned(-1);
2043 return Entry;
2044 }
2045 static inline EditEntry getTombstoneKey() {
2046 EditEntry Entry;
2047 Entry.Offset = unsigned(-2);
2048 return Entry;
2049 }
2050 static unsigned getHashValue(const EditEntry& Val) {
2051 return (unsigned)llvm::hash_combine(Val.File, Val.Offset, Val.RemoveLen,
2052 Val.Text);
2053 }
2054 static bool isEqual(const EditEntry &LHS, const EditEntry &RHS) {
2055 return LHS.File == RHS.File &&
2056 LHS.Offset == RHS.Offset &&
2057 LHS.RemoveLen == RHS.RemoveLen &&
2058 LHS.Text == RHS.Text;
2059 }
2060};
2061} // end namespace llvm
2062
2063namespace {
2064class RemapFileParser {
2065 FileManager &FileMgr;
2066
2067public:
2068 RemapFileParser(FileManager &FileMgr) : FileMgr(FileMgr) { }
2069
2070 bool parse(StringRef File, SmallVectorImpl<EditEntry> &Entries) {
2071 using namespace llvm::yaml;
2072
2073 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
2074 llvm::MemoryBuffer::getFile(File);
2075 if (!FileBufOrErr)
2076 return true;
2077
2078 llvm::SourceMgr SM;
2079 Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(), SM);
2080 document_iterator I = YAMLStream.begin();
2081 if (I == YAMLStream.end())
2082 return true;
2083 Node *Root = I->getRoot();
2084 if (!Root)
2085 return true;
2086
2087 SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root);
2088 if (!SeqNode)
2089 return true;
2090
2091 for (SequenceNode::iterator
2092 AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) {
2093 MappingNode *MapNode = dyn_cast<MappingNode>(&*AI);
2094 if (!MapNode)
2095 continue;
2096 parseEdit(MapNode, Entries);
2097 }
2098
2099 return false;
2100 }
2101
2102private:
2103 void parseEdit(llvm::yaml::MappingNode *Node,
2104 SmallVectorImpl<EditEntry> &Entries) {
2105 using namespace llvm::yaml;
2106 EditEntry Entry;
2107 bool Ignore = false;
2108
2109 for (MappingNode::iterator
2110 KVI = Node->begin(), KVE = Node->end(); KVI != KVE; ++KVI) {
2111 ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey());
2112 if (!KeyString)
2113 continue;
2114 SmallString<10> KeyStorage;
2115 StringRef Key = KeyString->getValue(KeyStorage);
2116
2117 ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue());
2118 if (!ValueString)
2119 continue;
2120 SmallString<64> ValueStorage;
2121 StringRef Val = ValueString->getValue(ValueStorage);
2122
2123 if (Key == "file") {
2124 if (auto File = FileMgr.getOptionalFileRef(Val))
2125 Entry.File = File;
2126 else
2127 Ignore = true;
2128 } else if (Key == "offset") {
2129 if (Val.getAsInteger(10, Entry.Offset))
2130 Ignore = true;
2131 } else if (Key == "remove") {
2132 if (Val.getAsInteger(10, Entry.RemoveLen))
2133 Ignore = true;
2134 } else if (Key == "text") {
2135 Entry.Text = std::string(Val);
2136 }
2137 }
2138
2139 if (!Ignore)
2140 Entries.push_back(Entry);
2141 }
2142};
2143} // end anonymous namespace
2144
2145static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) {
2146 Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
2147 << Err.str();
2148 return true;
2149}
2150
2151static std::string applyEditsToTemp(FileEntryRef FE,
2152 ArrayRef<EditEntry> Edits,
2153 FileManager &FileMgr,
2155 using namespace llvm::sys;
2156
2157 SourceManager SM(Diag, FileMgr);
2158 FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
2159 LangOptions LangOpts;
2160 edit::EditedSource Editor(SM, LangOpts);
2162 I = Edits.begin(), E = Edits.end(); I != E; ++I) {
2163 const EditEntry &Entry = *I;
2164 assert(Entry.File == FE);
2166 SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset);
2168 if (Entry.RemoveLen != 0) {
2170 Loc.getLocWithOffset(Entry.RemoveLen));
2171 }
2172
2173 edit::Commit commit(Editor);
2174 if (Range.isInvalid()) {
2175 commit.insert(Loc, Entry.Text);
2176 } else if (Entry.Text.empty()) {
2177 commit.remove(Range);
2178 } else {
2179 commit.replace(Range, Entry.Text);
2180 }
2181 Editor.commit(commit);
2182 }
2183
2184 Rewriter rewriter(SM, LangOpts);
2185 RewritesReceiver Rec(rewriter);
2186 Editor.applyRewrites(Rec, /*adjustRemovals=*/false);
2187
2188 const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
2189 SmallString<512> NewText;
2190 llvm::raw_svector_ostream OS(NewText);
2191 Buf->write(OS);
2192
2193 SmallString<64> TempPath;
2194 int FD;
2195 if (fs::createTemporaryFile(path::filename(FE.getName()),
2196 path::extension(FE.getName()).drop_front(), FD,
2197 TempPath)) {
2198 reportDiag("Could not create file: " + TempPath.str(), Diag);
2199 return std::string();
2200 }
2201
2202 llvm::raw_fd_ostream TmpOut(FD, /*shouldClose=*/true);
2203 TmpOut.write(NewText.data(), NewText.size());
2204 TmpOut.close();
2205
2206 return std::string(TempPath.str());
2207}
2208
2210 std::vector<std::pair<std::string,std::string> > &remap,
2211 ArrayRef<StringRef> remapFiles,
2212 DiagnosticConsumer *DiagClient) {
2213 bool hasErrorOccurred = false;
2214
2215 FileSystemOptions FSOpts;
2216 FileManager FileMgr(FSOpts);
2217 RemapFileParser Parser(FileMgr);
2218
2221 new DiagnosticsEngine(DiagID, new DiagnosticOptions,
2222 DiagClient, /*ShouldOwnClient=*/false));
2223
2224 typedef llvm::DenseMap<FileEntryRef, std::vector<EditEntry> >
2225 FileEditEntriesTy;
2226 FileEditEntriesTy FileEditEntries;
2227
2228 llvm::DenseSet<EditEntry> EntriesSet;
2229
2231 I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
2233 if (Parser.parse(*I, Entries))
2234 continue;
2235
2237 EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) {
2238 EditEntry &Entry = *EI;
2239 if (!Entry.File)
2240 continue;
2241 std::pair<llvm::DenseSet<EditEntry>::iterator, bool>
2242 Insert = EntriesSet.insert(Entry);
2243 if (!Insert.second)
2244 continue;
2245
2246 FileEditEntries[*Entry.File].push_back(Entry);
2247 }
2248 }
2249
2250 for (FileEditEntriesTy::iterator
2251 I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) {
2252 std::string TempFile = applyEditsToTemp(I->first, I->second,
2253 FileMgr, *Diags);
2254 if (TempFile.empty()) {
2255 hasErrorOccurred = true;
2256 continue;
2257 }
2258
2259 remap.emplace_back(std::string(I->first.getName()), TempFile);
2260 }
2261
2262 return hasErrorOccurred;
2263}
Defines the clang::ASTContext interface.
DynTypedNode Node
StringRef P
#define SM(sm)
Definition: Cuda.cpp:80
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:1048
Defines the clang::FileManager interface and associated types.
StringRef Text
Definition: Format.cpp:2937
#define X(type, name)
Definition: Value.h:142
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static bool IsVoidStarType(QualType Ty)
Definition: ObjCMT.cpp:1354
static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, llvm::SmallVectorImpl< ObjCProtocolDecl * > &ConformingProtocols, const NSAPI &NS, edit::Commit &commit)
Definition: ObjCMT.cpp:661
static bool AuditedType(QualType AT)
AuditedType - This routine audits the type AT and returns false if it is one of known CF object types...
Definition: ObjCMT.cpp:1368
static bool IsValidIdentifier(ASTContext &Ctx, const char *Name)
Definition: ObjCMT.cpp:1143
static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag)
Definition: ObjCMT.cpp:2145
static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2)
AvailabilityAttrsMatch - This routine checks that if comparing two availability attributes,...
Definition: ObjCMT.cpp:1079
static const char * PropertyMemoryAttribute(ASTContext &Context, QualType ArgType)
Definition: ObjCMT.cpp:428
static void ReplaceWithInstancetype(ASTContext &Ctx, const ObjCMigrateASTConsumer &ASTC, ObjCMethodDecl *OM)
Definition: ObjCMT.cpp:954
static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, const ObjCMethodDecl *Setter, const NSAPI &NS, edit::Commit &commit, unsigned LengthOfPrefix, bool Atomic, bool UseNsIosOnlyMacro, bool AvailabilityArgsMatch)
Definition: ObjCMT.cpp:454
static bool TypeIsInnerPointer(QualType T)
Definition: ObjCMT.cpp:1045
static StringRef GetUnsignedName(StringRef NSIntegerName)
Definition: ObjCMT.cpp:693
static bool hasSuperInitCall(const ObjCMethodDecl *MD)
Definition: ObjCMT.cpp:1690
static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D)
Definition: ObjCMT.cpp:564
static std::string applyEditsToTemp(FileEntryRef FE, ArrayRef< EditEntry > Edits, FileManager &FileMgr, DiagnosticsEngine &Diag)
Definition: ObjCMT.cpp:2151
static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y)
Check whether the two versions match.
Definition: ObjCMT.cpp:1070
static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2, bool &AvailabilityArgsMatch)
AttributesMatch - This routine checks list of attributes for two decls.
Definition: ObjCMT.cpp:1128
static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, StringRef NSIntegerName, bool NSOptions)
Definition: ObjCMT.cpp:704
static void rewriteToNSMacroDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, bool IsNSIntegerType)
Definition: ObjCMT.cpp:758
static bool ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, const ObjCImplementationDecl *ImpDecl, const ObjCInterfaceDecl *IDecl, ObjCProtocolDecl *Protocol)
Definition: ObjCMT.cpp:600
static void append_attr(std::string &PropertyString, const char *attr, bool &LParenAdded)
Definition: ObjCMT.cpp:385
static void MigrateBlockOrFunctionPointerTypeVariable(std::string &PropertyString, const std::string &TypeString, const char *name)
Definition: ObjCMT.cpp:397
static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC, ObjCMethodDecl *OM)
Definition: ObjCMT.cpp:977
static std::vector< std::string > getAllowListFilenames(StringRef DirPath)
Definition: ObjCMT.cpp:1986
static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, const EnumDecl *EnumDcl)
Definition: ObjCMT.cpp:789
static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2, bool &AvailabilityArgsMatch)
Definition: ObjCMT.cpp:1099
Defines the clang::Preprocessor interface.
static bool subscriptOperatorNeedsParens(const Expr *FullExpr)
SourceLocation Begin
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition: ASTConsumer.h:33
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: ASTConsumer.h:66
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D)
Handle the specified top-level declaration that occurred inside and ObjC container.
Definition: ASTConsumer.cpp:26
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
Definition: ASTConsumer.cpp:18
virtual void Initialize(ASTContext &Context)
Initialize - This is called to initialize the consumer, providing the ASTContext.
Definition: ASTConsumer.h:47
virtual void HandleInterestingDecl(DeclGroupRef D)
HandleInterestingDecl - Handle the specified interesting declaration.
Definition: ASTConsumer.cpp:22
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, const ObjCMethodDecl *MethodImp)
SourceManager & getSourceManager()
Definition: ASTContext.h:691
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1059
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2527
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
Definition: ASTContext.h:2543
IdentifierTable & Idents
Definition: ASTContext.h:630
const LangOptions & getLangOpts() const
Definition: ASTContext.h:761
QualType getObjCInstanceType()
Retrieve the Objective-C "instancetype" type, if already known; otherwise, returns a NULL type;.
Definition: ASTContext.h:1913
QualType getQualifiedType(SplitQualType split) const
Un-split a SplitQualType.
Definition: ASTContext.h:2125
const clang::PrintingPolicy & getPrintingPolicy() const
Definition: ASTContext.h:683
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2570
DiagnosticsEngine & getDiagnostics() const
void CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet< ObjCProtocolDecl *, 8 > &Protocols)
CollectInheritedProtocols - Collect all protocols in current class and those inherited by it.
An instance of this class corresponds to a call.
Definition: AnyCall.h:26
Attr - This represents one attribute.
Definition: Attr.h:40
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3847
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
FileManager & getFileManager() const
Return the current file manager to the caller.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
SourceManager & getSourceManager() const
Return the current source manager.
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1347
decl_iterator - Iterates through the declarations stored within this context.
Definition: DeclBase.h:2163
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1728
decl_iterator decls_end() const
Definition: DeclBase.h:2208
decl_iterator decls_begin() const
Definition: DeclBase.cpp:1498
iterator begin()
Definition: DeclGroup.h:99
iterator end()
Definition: DeclGroup.h:105
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
SourceLocation getEndLoc() const LLVM_READONLY
Definition: DeclBase.h:428
bool hasAttrs() const
Definition: DeclBase.h:502
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:576
SourceLocation getLocation() const
Definition: DeclBase.h:432
bool isDeprecated(std::string *Message=nullptr) const
Determine whether this declaration is marked 'deprecated'.
Definition: DeclBase.h:723
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: DeclBase.h:424
AttrVec & getAttrs()
Definition: DeclBase.h:508
bool hasAttr() const
Definition: DeclBase.h:560
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1740
Used for handling and querying diagnostic IDs.
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1542
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
Definition: Diagnostic.h:868
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
Definition: Diagnostic.h:645
Represents an enum.
Definition: Decl.h:3758
enumerator_range enumerators() const
Definition: Decl.h:3891
QualType getIntegerType() const
Return the integer type this enum decl corresponds to.
Definition: Decl.h:3918
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of enums.
Definition: Type.h:4959
This represents one expression.
Definition: Expr.h:110
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:3077
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3052
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition: FileEntry.h:57
StringRef getName() const
The name of this FileEntry.
Definition: FileEntry.h:61
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isValid() const
bool isInvalid() const
Implements support for file system lookup, file system caching, and directory search management.
Definition: FileManager.h:53
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
Definition: FileManager.h:234
bool FixupRelativePath(SmallVectorImpl< char > &path) const
If path is not absolute and FileSystemOptions set the working directory, the path is modified to be r...
Keeps track of options that affect how file operations are performed.
std::string ObjCMTAllowListPath
std::string OutputFile
The output file, if any.
@ ObjCMT_Instancetype
Enable migration of ObjC methods to 'instancetype'.
@ ObjCMT_DesignatedInitializer
Enable inferring NS_DESIGNATED_INITIALIZER for ObjC methods.
@ ObjCMT_Annotation
Enable annotation of ObjCMethods of all kinds.
@ ObjCMT_PropertyDotSyntax
Enable converting setter/getter expressions to property-dot syntx.
@ ObjCMT_ProtocolConformance
Enable migration to add conforming protocols.
@ ObjCMT_NsMacros
Enable migration to NS_ENUM/NS_OPTIONS macros.
@ ObjCMT_AtomicProperty
prefer 'atomic' property over 'nonatomic'.
@ ObjCMT_Literals
Enable migration to modern ObjC literals.
@ ObjCMT_ReadonlyProperty
Enable migration to modern ObjC readonly property.
@ ObjCMT_Subscripting
Enable migration to modern ObjC subscripting.
@ ObjCMT_NsAtomicIOSOnlyProperty
use NS_NONATOMIC_IOSONLY for property 'atomic' attribute
@ ObjCMT_ReadwriteProperty
Enable migration to modern ObjC readwrite property.
@ ObjCMT_ReturnsInnerPointerProperty
annotate property with NS_RETURNS_INNER_POINTER
FullExpr - Represents a "full-expression" node.
Definition: Expr.h:1019
Represents a function declaration or definition.
Definition: Decl.h:1919
param_iterator param_end()
Definition: Decl.h:2616
QualType getReturnType() const
Definition: Decl.h:2657
param_iterator param_begin()
Definition: Decl.h:2615
ArrayRef< ParmVarDecl * >::const_iterator param_const_iterator
Definition: Decl.h:2612
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:3616
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3094
One of these records is kept for each identifier that is lexed.
tok::TokenKind getTokenID() const
If this is a source-language token (e.g.
StringRef getName() const
Return the actual identifier string.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:83
bool isMacroDefined(StringRef Id) const
Returns true if Id is currently defined as a macro.
Definition: NSAPI.cpp:544
ASTContext & getASTContext() const
Definition: NSAPI.h:27
This represents a decl that may have a name.
Definition: Decl.h:247
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:268
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:274
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:313
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition: Decl.h:290
ObjCCategoryDecl - Represents a category declaration.
Definition: DeclObjC.h:2312
ObjCCategoryImplDecl - An object of this class encapsulates a category @implementation declaration.
Definition: DeclObjC.h:2531
ObjCContainerDecl - Represents a container for method declarations.
Definition: DeclObjC.h:941
ObjCMethodDecl * getMethod(Selector Sel, bool isInstance, bool AllowHidden=false) const
Definition: DeclObjC.cpp:92
method_range methods() const
Definition: DeclObjC.h:1009
instmeth_range instance_methods() const
Definition: DeclObjC.h:1026
instprop_range instance_properties() const
Definition: DeclObjC.h:975
ObjCMethodDecl * getInstanceMethod(Selector Sel, bool AllowHidden=false) const
Definition: DeclObjC.h:1059
ObjCPropertyImplDecl * FindPropertyImplDecl(IdentifierInfo *propertyId, ObjCPropertyQueryKind queryKind) const
FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl added to the list of thos...
Definition: DeclObjC.cpp:2259
const ObjCInterfaceDecl * getClassInterface() const
Definition: DeclObjC.h:2472
ObjCImplementationDecl - Represents a class definition - this is where method definitions are specifi...
Definition: DeclObjC.h:2584
Represents an ObjC class declaration.
Definition: DeclObjC.h:1147
ObjCInterfaceDecl * lookupInheritedClass(const IdentifierInfo *ICName)
lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super class whose name is passe...
Definition: DeclObjC.cpp:669
protocol_loc_iterator protocol_loc_end() const
Definition: DeclObjC.h:1391
SourceLocation getSuperClassLoc() const
Retrieve the starting location of the superclass.
Definition: DeclObjC.cpp:371
const ObjCProtocolList & getReferencedProtocols() const
Definition: DeclObjC.h:1322
ObjCProtocolDecl * lookupNestedProtocol(IdentifierInfo *Name)
Definition: DeclObjC.cpp:688
bool hasDesignatedInitializers() const
Returns true if this interface decl contains at least one initializer marked with the 'objc_designate...
Definition: DeclObjC.cpp:1608
ObjCInterfaceDecl * getSuperClass() const
Definition: DeclObjC.cpp:351
bool empty() const
Definition: DeclObjC.h:71
ObjCList - This is a simple template class used to hold various lists of decls etc,...
Definition: DeclObjC.h:82
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:942
bool isImplicit() const
Indicates whether the message send was implicitly generated by the implementation.
Definition: ExprObjC.h:1220
Expr ** getArgs()
Retrieve the arguments to this message, not including the receiver.
Definition: ExprObjC.h:1376
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1250
SourceLocation getSuperLoc() const
Retrieve the location of the 'super' keyword for a class or instance message to 'super',...
Definition: ExprObjC.h:1291
ObjCMethodFamily getMethodFamily() const
Definition: ExprObjC.h:1365
@ SuperInstance
The receiver is the instance of the superclass object.
Definition: ExprObjC.h:1097
@ Instance
The receiver is an object instance.
Definition: ExprObjC.h:1091
const ObjCMethodDecl * getMethodDecl() const
Definition: ExprObjC.h:1346
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
Definition: ExprObjC.h:1224
child_range children()
Definition: ExprObjC.cpp:326
SourceLocation getSelectorLoc(unsigned Index) const
Definition: ExprObjC.h:1415
unsigned getNumArgs() const
Return the number of actual arguments in this message, not counting the receiver.
Definition: ExprObjC.h:1372
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:138
bool hasBody() const override
Determine whether this method has a body.
Definition: DeclObjC.h:524
unsigned param_size() const
Definition: DeclObjC.h:349
bool isPropertyAccessor() const
Definition: DeclObjC.h:438
const ObjCPropertyDecl * findPropertyDecl(bool CheckOverrides=true) const
Returns the property associated with this method's selector.
Definition: DeclObjC.cpp:1378
param_const_iterator param_end() const
Definition: DeclObjC.h:360
SourceLocation getSelectorStartLoc() const
Definition: DeclObjC.h:290
param_const_iterator param_begin() const
Definition: DeclObjC.h:356
Stmt * getBody() const override
Retrieve the body of this method, if it has one.
Definition: DeclObjC.cpp:909
SourceLocation getEndLoc() const LLVM_READONLY
Definition: DeclObjC.cpp:1047
TypeSourceInfo * getReturnTypeSourceInfo() const
Definition: DeclObjC.h:345
const ParmVarDecl *const * param_const_iterator
Definition: DeclObjC.h:351
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: DeclObjC.h:284
Selector getSelector() const
Definition: DeclObjC.h:329
bool isInstanceMethod() const
Definition: DeclObjC.h:428
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Definition: DeclObjC.cpp:1053
QualType getReturnType() const
Definition: DeclObjC.h:331
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1211
SourceLocation getDeclaratorEndLoc() const
Returns the location where the declarator ends.
Definition: DeclObjC.h:281
Represents a pointer to an Objective C object.
Definition: Type.h:6395
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:729
Represents an Objective-C protocol declaration.
Definition: DeclObjC.h:2069
ObjCProtocolDecl * lookupProtocolNamed(IdentifierInfo *PName)
Definition: DeclObjC.cpp:1988
ObjCProtocolDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this Objective-C protocol.
Definition: DeclObjC.h:2280
Records preprocessor conditional directive regions and allows querying in which region source locatio...
Represents a parameter to a function.
Definition: Decl.h:1724
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:53
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2840
QualType getPointeeType() const
Definition: Type.h:2850
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, SourceLocation Loc)
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
SourceManager & getSourceManager() const
IdentifierTable & getIdentifierTable()
bool getRawToken(SourceLocation Loc, Token &Result, bool IgnoreWhiteSpace=false)
Relex the token at the specified location.
SelectorTable & getSelectorTable()
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Computes the source location just past the end of the token at this source location.
A (possibly-)qualified type.
Definition: Type.h:736
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:803
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition: Type.h:6787
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition: Type.h:1225
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:6840
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: Type.h:1120
The collection of all-type qualifiers we support.
Definition: Type.h:146
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition: Type.h:174
@ OCL_None
There is no lifetime qualification on this type.
Definition: Type.h:163
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition: Type.h:177
void removeObjCLifetime()
Definition: Type.h:357
bool hasObjCLifetime() const
Definition: Type.h:350
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4933
RecordDecl * getDecl() const
Definition: Type.h:4943
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
RewriteBuffer - As code is rewritten, SourceBuffer's from the original input with modifications get a...
Definition: RewriteBuffer.h:25
raw_ostream & write(raw_ostream &Stream) const
Write to Stream the result of applying all changes to the original buffer.
Definition: Rewriter.cpp:33
Rewriter - This is the main interface to the rewrite buffers.
Definition: Rewriter.h:32
const RewriteBuffer * getRewriteBufferFor(FileID FID) const
getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
Definition: Rewriter.h:198
std::map< FileID, RewriteBuffer >::iterator buffer_iterator
Definition: Rewriter.h:65
static Selector constructSetterSelector(IdentifierTable &Idents, SelectorTable &SelTable, const IdentifierInfo *Name)
Return the default setter selector for the given identifier.
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
IdentifierInfo * getIdentifierInfoForSlot(unsigned argIndex) const
Retrieve the identifier at a given position in the selector.
static ObjCInstanceTypeFamily getInstTypeMethodFamily(Selector sel)
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
Stmt - This represents one statement.
Definition: Stmt.h:72
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Stmt.cpp:349
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:325
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:337
SourceRange getBraceRange() const
Definition: Decl.h:3556
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Definition: Decl.h:3580
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
bool isLiteral() const
Return true if this is a "literal", like a numeric constant, string, etc.
Definition: Token.h:115
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:131
unsigned getLength() const
Definition: Token.h:134
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
Definition: Token.h:224
The top declaration context.
Definition: Decl.h:82
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Decl.h:3312
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:59
SourceLocation getEndLoc() const
Get the end source location.
Definition: TypeLoc.cpp:235
SourceLocation getBeginLoc() const
Get the begin source location.
Definition: TypeLoc.cpp:192
A container of type source information.
Definition: Type.h:6718
QualType getType() const
Return the type wrapped by this type source info.
Definition: Type.h:6729
bool isBlockPointerType() const
Definition: Type.h:7007
bool isVoidType() const
Definition: Type.h:7317
bool isObjCBuiltinType() const
Definition: Type.h:7178
bool isFunctionPointerType() const
Definition: Type.h:7033
bool isPointerType() const
Definition: Type.h:6999
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:7590
bool isObjCIdType() const
Definition: Type.h:7160
bool isObjCObjectPointerType() const
Definition: Type.h:7127
bool isAnyPointerType() const
Definition: Type.h:7003
bool isRealType() const
Definition: Type.cpp:2213
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7523
bool isObjCRetainableType() const
Definition: Type.cpp:4616
Represents the declaration of a typedef-name via the 'typedef' type specifier.
Definition: Decl.h:3429
TypeSourceInfo * getTypeSourceInfo() const
Definition: Decl.h:3377
QualType getType() const
Definition: Decl.h:714
A frontend action which simply wraps some other runtime-specified frontend action.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag)
bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag)
void remap(StringRef filePath, std::unique_ptr< llvm::MemoryBuffer > memBuf)
bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged)
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
Definition: ObjCMT.cpp:2006
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
Definition: ObjCMT.cpp:1981
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
Definition: ObjCMT.cpp:208
ObjCMigrateAction(std::unique_ptr< FrontendAction > WrappedAction, StringRef migrateDir, unsigned migrateAction)
Definition: ObjCMT.cpp:186
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
Definition: ObjCMT.cpp:196
bool insertWrap(StringRef before, CharSourceRange range, StringRef after)
Definition: Commit.cpp:103
bool insertFromRange(SourceLocation loc, CharSourceRange range, bool afterToken=false, bool beforePreviousInsertions=false)
Definition: Commit.cpp:64
bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)
Definition: Commit.cpp:48
bool insertAfterToken(SourceLocation loc, StringRef text, bool beforePreviousInsertions=false)
Definition: Commit.h:73
bool remove(CharSourceRange range)
Definition: Commit.cpp:91
bool insertBefore(SourceLocation loc, StringRef text)
Definition: Commit.h:78
bool replace(CharSourceRange range, StringRef text)
Definition: Commit.cpp:116
void applyRewrites(EditsReceiver &receiver, bool adjustRemovals=true)
bool commit(const Commit &commit)
An ArgEffect summarizes the retain count behavior on an argument or receiver to a function or method.
ArgEffectKind getKind() const
A Range represents the closed range [from, to].
RetEffect summarizes a call's retain/release behavior with respect to its return value.
Summary for a function with respect to ownership changes.
ArgEffect getReceiverEffect() const
getReceiverEffect - Returns the effect on the receiver of the call.
RetEffect getRetEffect() const
getRetEffect - Returns the effect on the return value of the call.
ArgEffect getArg(unsigned idx) const
getArg - Return the argument effect on the argument specified by idx (starting from 0).
SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx, bool IsDecl=false)
'Loc' is the end of a statement range.
Definition: Transforms.cpp:116
SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx, bool IsDecl=false)
'Loc' is the end of a statement range.
Definition: Transforms.cpp:128
bool getFileRemappingsFromFileList(std::vector< std::pair< std::string, std::string > > &remap, ArrayRef< StringRef > remapFiles, DiagnosticConsumer *DiagClient)
Get the set of file remappings from a list of files with remapping info.
Definition: ObjCMT.cpp:2209
const internal::VariadicAllOfMatcher< Attr > attr
Matches attributes.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit, const ParentMap *PMap)
bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
@ IncRef
The argument has its reference count increased by 1.
@ DecRef
The argument has its reference count decreased by 1.
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:202
RangeSelector range(RangeSelector Begin, RangeSelector End)
DEPRECATED. Use enclose.
Definition: RangeSelector.h:41
ASTEdit remove(RangeSelector S)
Removes the source selected by S.
@ Rewrite
We are substituting template parameters for (typically) other template parameters in order to rewrite...
LLVM_READONLY char toLowercase(char c)
Converts the given ASCII character to its lowercase equivalent.
Definition: CharInfo.h:208
LLVM_READONLY bool isUppercase(unsigned char c)
Return true if this character is an uppercase ASCII letter: [A-Z].
Definition: CharInfo.h:111
ObjCMethodFamily
A family of Objective-C methods.
@ OMF_mutableCopy
@ Property
The type of a property.
ObjCInstanceTypeFamily
A family of Objective-C methods.
@ OIT_Dictionary
@ OIT_ReturnsSelf
LLVM_READONLY bool isAsciiIdentifierStart(unsigned char c, bool AllowDollar=false)
Returns true if this is a valid first character of a C identifier, which is [a-zA-Z_].
Definition: CharInfo.h:54
YAML serialization mapping.
Definition: Dominators.h:30
Definition: Format.h:5078
#define false
Definition: stdbool.h:22
Describes how types, statements, expressions, and declarations should be printed.
Definition: PrettyPrinter.h:57
unsigned SuppressStrongLifetime
When true, suppress printing of the __strong lifetime qualifier in ARC.
unsigned SuppressLifetimeQualifiers
When true, suppress printing of lifetime qualifier in ARC.
static bool isEqual(const EditEntry &LHS, const EditEntry &RHS)
Definition: ObjCMT.cpp:2054
static EditEntry getTombstoneKey()
Definition: ObjCMT.cpp:2045
static unsigned getHashValue(const EditEntry &Val)
Definition: ObjCMT.cpp:2050
static EditEntry getEmptyKey()
Definition: ObjCMT.cpp:2040