clang 20.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;
39using llvm::RewriteBuffer;
40
41namespace {
42
43class ObjCMigrateASTConsumer : public ASTConsumer {
44 enum CF_BRIDGING_KIND {
45 CF_BRIDGING_NONE,
46 CF_BRIDGING_ENABLE,
47 CF_BRIDGING_MAY_INCLUDE
48 };
49
50 void migrateDecl(Decl *D);
51 void migrateObjCContainerDecl(ASTContext &Ctx, ObjCContainerDecl *D);
52 void migrateProtocolConformance(ASTContext &Ctx,
53 const ObjCImplementationDecl *ImpDecl);
54 void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
55 bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
56 const TypedefDecl *TypedefDcl);
57 void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
58 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
59 ObjCMethodDecl *OM);
60 bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
61 void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
62 void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
63 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
65 ObjCInstanceTypeFamily OIT_Family = OIT_None);
66
67 void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
68 void AddCFAnnotations(ASTContext &Ctx,
69 const RetainSummary *RS,
70 const FunctionDecl *FuncDecl, bool ResultAnnotated);
71 void AddCFAnnotations(ASTContext &Ctx,
72 const RetainSummary *RS,
73 const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
74
75 void AnnotateImplicitBridging(ASTContext &Ctx);
76
77 CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
78 const FunctionDecl *FuncDecl);
79
80 void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
81
82 void migrateAddMethodAnnotation(ASTContext &Ctx,
83 const ObjCMethodDecl *MethodDecl);
84
85 void inferDesignatedInitializers(ASTContext &Ctx,
86 const ObjCImplementationDecl *ImplD);
87
88 bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc);
89
90 std::unique_ptr<RetainSummaryManager> Summaries;
91
92public:
93 std::string MigrateDir;
94 unsigned ASTMigrateActions;
95 FileID FileId;
96 const TypedefDecl *NSIntegerTypedefed;
97 const TypedefDecl *NSUIntegerTypedefed;
98 std::unique_ptr<NSAPI> NSAPIObj;
99 std::unique_ptr<edit::EditedSource> Editor;
100 FileRemapper &Remapper;
101 FileManager &FileMgr;
102 const PPConditionalDirectiveRecord *PPRec;
103 Preprocessor &PP;
104 bool IsOutputFile;
105 bool FoundationIncluded;
107 llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
108 llvm::StringSet<> AllowListFilenames;
109
110 RetainSummaryManager &getSummaryManager(ASTContext &Ctx) {
111 if (!Summaries)
112 Summaries.reset(new RetainSummaryManager(Ctx,
113 /*TrackNSCFObjects=*/true,
114 /*trackOSObjects=*/false));
115 return *Summaries;
116 }
117
118 ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions,
119 FileRemapper &remapper, FileManager &fileMgr,
120 const PPConditionalDirectiveRecord *PPRec,
121 Preprocessor &PP, bool isOutputFile,
122 ArrayRef<std::string> AllowList)
123 : MigrateDir(migrateDir), ASTMigrateActions(astMigrateActions),
124 NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
125 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
126 IsOutputFile(isOutputFile), FoundationIncluded(false) {
127 AllowListFilenames.insert(AllowList.begin(), AllowList.end());
128 }
129
130protected:
131 void Initialize(ASTContext &Context) override {
132 NSAPIObj.reset(new NSAPI(Context));
133 Editor.reset(new edit::EditedSource(Context.getSourceManager(),
134 Context.getLangOpts(),
135 PPRec));
136 }
137
138 bool HandleTopLevelDecl(DeclGroupRef DG) override {
139 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
140 migrateDecl(*I);
141 return true;
142 }
143 void HandleInterestingDecl(DeclGroupRef DG) override {
144 // Ignore decls from the PCH.
145 }
147 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
148 }
149
150 void HandleTranslationUnit(ASTContext &Ctx) override;
151
152 bool canModifyFile(StringRef Path) {
153 if (AllowListFilenames.empty())
154 return true;
155 return AllowListFilenames.contains(llvm::sys::path::filename(Path));
156 }
157 bool canModifyFile(OptionalFileEntryRef FE) {
158 if (!FE)
159 return false;
160 return canModifyFile(FE->getName());
161 }
162 bool canModifyFile(FileID FID) {
163 if (FID.isInvalid())
164 return false;
165 return canModifyFile(PP.getSourceManager().getFileEntryRefForID(FID));
166 }
167
168 bool canModify(const Decl *D) {
169 if (!D)
170 return false;
171 if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(D))
172 return canModify(CatImpl->getCategoryDecl());
173 if (const ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D))
174 return canModify(Impl->getClassInterface());
175 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
176 return canModify(cast<Decl>(MD->getDeclContext()));
177
179 return canModifyFile(FID);
180 }
181};
182
183} // end anonymous namespace
184
186 std::unique_ptr<FrontendAction> WrappedAction, StringRef migrateDir,
187 unsigned migrateAction)
188 : WrapperFrontendAction(std::move(WrappedAction)), MigrateDir(migrateDir),
189 ObjCMigAction(migrateAction), CompInst(nullptr) {
190 if (MigrateDir.empty())
191 MigrateDir = "."; // user current directory if none is given.
192}
193
194std::unique_ptr<ASTConsumer>
197 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
198 CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
199 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
200 Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
201 Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
202 MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec,
203 CompInst->getPreprocessor(), false, std::nullopt));
204 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
205}
206
208 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
209 /*ignoreIfFilesChanged=*/true);
210 CompInst = &CI;
212 return true;
213}
214
215namespace {
216 // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp
218 const Expr* Expr = FullExpr->IgnoreImpCasts();
219 return !(isa<ArraySubscriptExpr>(Expr) || isa<CallExpr>(Expr) ||
220 isa<DeclRefExpr>(Expr) || isa<CXXNamedCastExpr>(Expr) ||
221 isa<CXXConstructExpr>(Expr) || isa<CXXThisExpr>(Expr) ||
222 isa<CXXTypeidExpr>(Expr) ||
223 isa<CXXUnresolvedConstructExpr>(Expr) ||
224 isa<ObjCMessageExpr>(Expr) || isa<ObjCPropertyRefExpr>(Expr) ||
225 isa<ObjCProtocolExpr>(Expr) || isa<MemberExpr>(Expr) ||
226 isa<ObjCIvarRefExpr>(Expr) || isa<ParenExpr>(FullExpr) ||
227 isa<ParenListExpr>(Expr) || isa<SizeOfPackExpr>(Expr));
228 }
229
230 /// - Rewrite message expression for Objective-C setter and getters into
231 /// property-dot syntax.
232 bool rewriteToPropertyDotSyntax(const ObjCMessageExpr *Msg,
233 Preprocessor &PP,
234 const NSAPI &NS, edit::Commit &commit,
235 const ParentMap *PMap) {
236 if (!Msg || Msg->isImplicit() ||
239 return false;
240 if (const Expr *Receiver = Msg->getInstanceReceiver())
241 if (Receiver->getType()->isObjCBuiltinType())
242 return false;
243
244 const ObjCMethodDecl *Method = Msg->getMethodDecl();
245 if (!Method)
246 return false;
247 if (!Method->isPropertyAccessor())
248 return false;
249
250 const ObjCPropertyDecl *Prop = Method->findPropertyDecl();
251 if (!Prop)
252 return false;
253
254 SourceRange MsgRange = Msg->getSourceRange();
255 bool ReceiverIsSuper =
257 // for 'super' receiver is nullptr.
258 const Expr *receiver = Msg->getInstanceReceiver();
259 bool NeedsParen =
260 ReceiverIsSuper ? false : subscriptOperatorNeedsParens(receiver);
261 bool IsGetter = (Msg->getNumArgs() == 0);
262 if (IsGetter) {
263 // Find space location range between receiver expression and getter method.
264 SourceLocation BegLoc =
265 ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
266 BegLoc = PP.getLocForEndOfToken(BegLoc);
267 SourceLocation EndLoc = Msg->getSelectorLoc(0);
268 SourceRange SpaceRange(BegLoc, EndLoc);
269 std::string PropertyDotString;
270 // rewrite getter method expression into: receiver.property or
271 // (receiver).property
272 if (NeedsParen) {
273 commit.insertBefore(receiver->getBeginLoc(), "(");
274 PropertyDotString = ").";
275 }
276 else
277 PropertyDotString = ".";
278 PropertyDotString += Prop->getName();
279 commit.replace(SpaceRange, PropertyDotString);
280
281 // remove '[' ']'
282 commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
283 commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
284 } else {
285 if (NeedsParen)
286 commit.insertWrap("(", receiver->getSourceRange(), ")");
287 std::string PropertyDotString = ".";
288 PropertyDotString += Prop->getName();
289 PropertyDotString += " =";
290 const Expr*const* Args = Msg->getArgs();
291 const Expr *RHS = Args[0];
292 if (!RHS)
293 return false;
294 SourceLocation BegLoc =
295 ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
296 BegLoc = PP.getLocForEndOfToken(BegLoc);
297 SourceLocation EndLoc = RHS->getBeginLoc();
298 EndLoc = EndLoc.getLocWithOffset(-1);
299 const char *colon = PP.getSourceManager().getCharacterData(EndLoc);
300 // Add a space after '=' if there is no space between RHS and '='
301 if (colon && colon[0] == ':')
302 PropertyDotString += " ";
303 SourceRange Range(BegLoc, EndLoc);
304 commit.replace(Range, PropertyDotString);
305 // remove '[' ']'
306 commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
307 commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
308 }
309 return true;
310 }
311
312class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
313 ObjCMigrateASTConsumer &Consumer;
314 ParentMap &PMap;
315
316public:
317 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
318 : Consumer(consumer), PMap(PMap) { }
319
320 bool shouldVisitTemplateInstantiations() const { return false; }
321 bool shouldWalkTypesOfTypeLocs() const { return false; }
322
323 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
324 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
325 edit::Commit commit(*Consumer.Editor);
326 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
327 Consumer.Editor->commit(commit);
328 }
329
330 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
331 edit::Commit commit(*Consumer.Editor);
332 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
333 Consumer.Editor->commit(commit);
334 }
335
336 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_PropertyDotSyntax) {
337 edit::Commit commit(*Consumer.Editor);
338 rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
339 commit, &PMap);
340 Consumer.Editor->commit(commit);
341 }
342
343 return true;
344 }
345
346 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
347 // Do depth first; we want to rewrite the subexpressions first so that if
348 // we have to move expressions we will move them already rewritten.
349 for (Stmt *SubStmt : E->children())
350 if (!TraverseStmt(SubStmt))
351 return false;
352
353 return WalkUpFromObjCMessageExpr(E);
354 }
355};
356
357class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
358 ObjCMigrateASTConsumer &Consumer;
359 std::unique_ptr<ParentMap> PMap;
360
361public:
362 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
363
364 bool shouldVisitTemplateInstantiations() const { return false; }
365 bool shouldWalkTypesOfTypeLocs() const { return false; }
366
367 bool TraverseStmt(Stmt *S) {
368 PMap.reset(new ParentMap(S));
369 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
370 return true;
371 }
372};
373} // end anonymous namespace
374
375void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
376 if (!D)
377 return;
378 if (isa<ObjCMethodDecl>(D))
379 return; // Wait for the ObjC container declaration.
380
381 BodyMigrator(*this).TraverseDecl(D);
382}
383
384static void append_attr(std::string &PropertyString, const char *attr,
385 bool &LParenAdded) {
386 if (!LParenAdded) {
387 PropertyString += "(";
388 LParenAdded = true;
389 }
390 else
391 PropertyString += ", ";
392 PropertyString += attr;
393}
394
395static
396void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
397 const std::string& TypeString,
398 const char *name) {
399 const char *argPtr = TypeString.c_str();
400 int paren = 0;
401 while (*argPtr) {
402 switch (*argPtr) {
403 case '(':
404 PropertyString += *argPtr;
405 paren++;
406 break;
407 case ')':
408 PropertyString += *argPtr;
409 paren--;
410 break;
411 case '^':
412 case '*':
413 PropertyString += (*argPtr);
414 if (paren == 1) {
415 PropertyString += name;
416 name = "";
417 }
418 break;
419 default:
420 PropertyString += *argPtr;
421 break;
422 }
423 argPtr++;
424 }
425}
426
427static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
428 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
429 bool RetainableObject = ArgType->isObjCRetainableType();
430 if (RetainableObject &&
431 (propertyLifetime == Qualifiers::OCL_Strong
432 || propertyLifetime == Qualifiers::OCL_None)) {
433 if (const ObjCObjectPointerType *ObjPtrTy =
434 ArgType->getAs<ObjCObjectPointerType>()) {
435 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
436 if (IDecl &&
437 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
438 return "copy";
439 else
440 return "strong";
441 }
442 else if (ArgType->isBlockPointerType())
443 return "copy";
444 } else if (propertyLifetime == Qualifiers::OCL_Weak)
445 // TODO. More precise determination of 'weak' attribute requires
446 // looking into setter's implementation for backing weak ivar.
447 return "weak";
448 else if (RetainableObject)
449 return ArgType->isBlockPointerType() ? "copy" : "strong";
450 return nullptr;
451}
452
453static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
454 const ObjCMethodDecl *Setter,
455 const NSAPI &NS, edit::Commit &commit,
456 unsigned LengthOfPrefix,
457 bool Atomic, bool UseNsIosOnlyMacro,
458 bool AvailabilityArgsMatch) {
459 ASTContext &Context = NS.getASTContext();
460 bool LParenAdded = false;
461 std::string PropertyString = "@property ";
462 if (UseNsIosOnlyMacro && NS.isMacroDefined("NS_NONATOMIC_IOSONLY")) {
463 PropertyString += "(NS_NONATOMIC_IOSONLY";
464 LParenAdded = true;
465 } else if (!Atomic) {
466 PropertyString += "(nonatomic";
467 LParenAdded = true;
468 }
469
470 std::string PropertyNameString = Getter->getNameAsString();
471 StringRef PropertyName(PropertyNameString);
472 if (LengthOfPrefix > 0) {
473 if (!LParenAdded) {
474 PropertyString += "(getter=";
475 LParenAdded = true;
476 }
477 else
478 PropertyString += ", getter=";
479 PropertyString += PropertyNameString;
480 }
481 // Property with no setter may be suggested as a 'readonly' property.
482 if (!Setter)
483 append_attr(PropertyString, "readonly", LParenAdded);
484
485
486 // Short circuit 'delegate' properties that contain the name "delegate" or
487 // "dataSource", or have exact name "target" to have 'assign' attribute.
488 if (PropertyName == "target" || PropertyName.contains("delegate") ||
489 PropertyName.contains("dataSource")) {
490 QualType QT = Getter->getReturnType();
491 if (!QT->isRealType())
492 append_attr(PropertyString, "assign", LParenAdded);
493 } else if (!Setter) {
494 QualType ResType = Context.getCanonicalType(Getter->getReturnType());
495 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
496 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
497 } else {
498 const ParmVarDecl *argDecl = *Setter->param_begin();
499 QualType ArgType = Context.getCanonicalType(argDecl->getType());
500 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
501 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
502 }
503 if (LParenAdded)
504 PropertyString += ')';
505 QualType RT = Getter->getReturnType();
506 if (!RT->getAs<TypedefType>()) {
507 // strip off any ARC lifetime qualifier.
508 QualType CanResultTy = Context.getCanonicalType(RT);
509 if (CanResultTy.getQualifiers().hasObjCLifetime()) {
510 Qualifiers Qs = CanResultTy.getQualifiers();
512 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
513 }
514 }
515 PropertyString += " ";
516 PrintingPolicy SubPolicy(Context.getPrintingPolicy());
517 SubPolicy.SuppressStrongLifetime = true;
518 SubPolicy.SuppressLifetimeQualifiers = true;
519 std::string TypeString = RT.getAsString(SubPolicy);
520 if (LengthOfPrefix > 0) {
521 // property name must strip off "is" and lower case the first character
522 // after that; e.g. isContinuous will become continuous.
523 StringRef PropertyNameStringRef(PropertyNameString);
524 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
525 PropertyNameString = std::string(PropertyNameStringRef);
526 bool NoLowering = (isUppercase(PropertyNameString[0]) &&
527 PropertyNameString.size() > 1 &&
528 isUppercase(PropertyNameString[1]));
529 if (!NoLowering)
530 PropertyNameString[0] = toLowercase(PropertyNameString[0]);
531 }
532 if (RT->isBlockPointerType() || RT->isFunctionPointerType())
534 TypeString,
535 PropertyNameString.c_str());
536 else {
537 char LastChar = TypeString[TypeString.size()-1];
538 PropertyString += TypeString;
539 if (LastChar != '*')
540 PropertyString += ' ';
541 PropertyString += PropertyNameString;
542 }
543 SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
544 Selector GetterSelector = Getter->getSelector();
545
546 SourceLocation EndGetterSelectorLoc =
547 StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
549 EndGetterSelectorLoc),
550 PropertyString);
551 if (Setter && AvailabilityArgsMatch) {
552 SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
553 // Get location past ';'
554 EndLoc = EndLoc.getLocWithOffset(1);
555 SourceLocation BeginOfSetterDclLoc = Setter->getBeginLoc();
556 // FIXME. This assumes that setter decl; is immediately preceded by eoln.
557 // It is trying to remove the setter method decl. line entirely.
558 BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
559 commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
560 }
561}
562
564 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D)) {
565 StringRef Name = CatDecl->getName();
566 return Name.ends_with("Deprecated");
567 }
568 return false;
569}
570
571void ObjCMigrateASTConsumer::migrateObjCContainerDecl(ASTContext &Ctx,
574 return;
575
576 for (auto *Method : D->methods()) {
577 if (Method->isDeprecated())
578 continue;
579 bool PropertyInferred = migrateProperty(Ctx, D, Method);
580 // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to
581 // the getter method as it ends up on the property itself which we don't want
582 // to do unless -objcmt-returns-innerpointer-property option is on.
583 if (!PropertyInferred ||
585 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
586 migrateNsReturnsInnerPointer(Ctx, Method);
587 }
589 return;
590
591 for (auto *Prop : D->instance_properties()) {
592 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
593 !Prop->isDeprecated())
594 migratePropertyNsReturnsInnerPointer(Ctx, Prop);
595 }
596}
597
598static bool
600 const ObjCImplementationDecl *ImpDecl,
601 const ObjCInterfaceDecl *IDecl,
602 ObjCProtocolDecl *Protocol) {
603 // In auto-synthesis, protocol properties are not synthesized. So,
604 // a conforming protocol must have its required properties declared
605 // in class interface.
606 bool HasAtleastOneRequiredProperty = false;
607 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
608 for (const auto *Property : PDecl->instance_properties()) {
609 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
610 continue;
611 HasAtleastOneRequiredProperty = true;
612 DeclContext::lookup_result R = IDecl->lookup(Property->getDeclName());
613 if (R.empty()) {
614 // Relax the rule and look into class's implementation for a synthesize
615 // or dynamic declaration. Class is implementing a property coming from
616 // another protocol. This still makes the target protocol as conforming.
617 if (!ImpDecl->FindPropertyImplDecl(
618 Property->getDeclName().getAsIdentifierInfo(),
619 Property->getQueryKind()))
620 return false;
621 } else if (auto *ClassProperty = R.find_first<ObjCPropertyDecl>()) {
622 if ((ClassProperty->getPropertyAttributes() !=
623 Property->getPropertyAttributes()) ||
624 !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
625 return false;
626 } else
627 return false;
628 }
629
630 // At this point, all required properties in this protocol conform to those
631 // declared in the class.
632 // Check that class implements the required methods of the protocol too.
633 bool HasAtleastOneRequiredMethod = false;
634 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
635 if (PDecl->meth_begin() == PDecl->meth_end())
636 return HasAtleastOneRequiredProperty;
637 for (const auto *MD : PDecl->methods()) {
638 if (MD->isImplicit())
639 continue;
640 if (MD->getImplementationControl() == ObjCImplementationControl::Optional)
641 continue;
642 DeclContext::lookup_result R = ImpDecl->lookup(MD->getDeclName());
643 if (R.empty())
644 return false;
645 bool match = false;
646 HasAtleastOneRequiredMethod = true;
647 for (NamedDecl *ND : R)
648 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(ND))
649 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
650 match = true;
651 break;
652 }
653 if (!match)
654 return false;
655 }
656 }
657 return HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod;
658}
659
661 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
662 const NSAPI &NS, edit::Commit &commit) {
663 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
664 std::string ClassString;
665 SourceLocation EndLoc =
666 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
667
668 if (Protocols.empty()) {
669 ClassString = '<';
670 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
671 ClassString += ConformingProtocols[i]->getNameAsString();
672 if (i != (e-1))
673 ClassString += ", ";
674 }
675 ClassString += "> ";
676 }
677 else {
678 ClassString = ", ";
679 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
680 ClassString += ConformingProtocols[i]->getNameAsString();
681 if (i != (e-1))
682 ClassString += ", ";
683 }
685 EndLoc = *PL;
686 }
687
688 commit.insertAfterToken(EndLoc, ClassString);
689 return true;
690}
691
692static StringRef GetUnsignedName(StringRef NSIntegerName) {
693 StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName)
694 .Case("int8_t", "uint8_t")
695 .Case("int16_t", "uint16_t")
696 .Case("int32_t", "uint32_t")
697 .Case("NSInteger", "NSUInteger")
698 .Case("int64_t", "uint64_t")
699 .Default(NSIntegerName);
700 return UnsignedName;
701}
702
703static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
704 const TypedefDecl *TypedefDcl,
705 const NSAPI &NS, edit::Commit &commit,
706 StringRef NSIntegerName,
707 bool NSOptions) {
708 std::string ClassString;
709 if (NSOptions) {
710 ClassString = "typedef NS_OPTIONS(";
711 ClassString += GetUnsignedName(NSIntegerName);
712 }
713 else {
714 ClassString = "typedef NS_ENUM(";
715 ClassString += NSIntegerName;
716 }
717 ClassString += ", ";
718
719 ClassString += TypedefDcl->getIdentifier()->getName();
720 ClassString += ')';
721 SourceRange R(EnumDcl->getBeginLoc(), EnumDcl->getBeginLoc());
722 commit.replace(R, ClassString);
723 SourceLocation EndOfEnumDclLoc = EnumDcl->getEndLoc();
724 EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
725 NS.getASTContext(), /*IsDecl*/true);
726 if (EndOfEnumDclLoc.isValid()) {
727 SourceRange EnumDclRange(EnumDcl->getBeginLoc(), EndOfEnumDclLoc);
728 commit.insertFromRange(TypedefDcl->getBeginLoc(), EnumDclRange);
729 }
730 else
731 return false;
732
733 SourceLocation EndTypedefDclLoc = TypedefDcl->getEndLoc();
734 EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
735 NS.getASTContext(), /*IsDecl*/true);
736 if (EndTypedefDclLoc.isValid()) {
737 SourceRange TDRange(TypedefDcl->getBeginLoc(), EndTypedefDclLoc);
738 commit.remove(TDRange);
739 }
740 else
741 return false;
742
743 EndOfEnumDclLoc =
745 /*IsDecl*/ true);
746 if (EndOfEnumDclLoc.isValid()) {
747 SourceLocation BeginOfEnumDclLoc = EnumDcl->getBeginLoc();
748 // FIXME. This assumes that enum decl; is immediately preceded by eoln.
749 // It is trying to remove the enum decl. lines entirely.
750 BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
751 commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
752 return true;
753 }
754 return false;
755}
756
758 const EnumDecl *EnumDcl,
759 const TypedefDecl *TypedefDcl,
760 const NSAPI &NS, edit::Commit &commit,
761 bool IsNSIntegerType) {
762 QualType DesignatedEnumType = EnumDcl->getIntegerType();
763 assert(!DesignatedEnumType.isNull()
764 && "rewriteToNSMacroDecl - underlying enum type is null");
765
766 PrintingPolicy Policy(Ctx.getPrintingPolicy());
767 std::string TypeString = DesignatedEnumType.getAsString(Policy);
768 std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS(";
769 ClassString += TypeString;
770 ClassString += ", ";
771
772 ClassString += TypedefDcl->getIdentifier()->getName();
773 ClassString += ") ";
774 SourceLocation EndLoc = EnumDcl->getBraceRange().getBegin();
775 if (EndLoc.isInvalid())
776 return;
778 CharSourceRange::getCharRange(EnumDcl->getBeginLoc(), EndLoc);
779 commit.replace(R, ClassString);
780 // This is to remove spaces between '}' and typedef name.
781 SourceLocation StartTypedefLoc = EnumDcl->getEndLoc();
782 StartTypedefLoc = StartTypedefLoc.getLocWithOffset(+1);
783 SourceLocation EndTypedefLoc = TypedefDcl->getEndLoc();
784
785 commit.remove(SourceRange(StartTypedefLoc, EndTypedefLoc));
786}
787
789 const EnumDecl *EnumDcl) {
790 bool PowerOfTwo = true;
791 bool AllHexdecimalEnumerator = true;
792 uint64_t MaxPowerOfTwoVal = 0;
793 for (auto *Enumerator : EnumDcl->enumerators()) {
794 const Expr *InitExpr = Enumerator->getInitExpr();
795 if (!InitExpr) {
796 PowerOfTwo = false;
797 AllHexdecimalEnumerator = false;
798 continue;
799 }
800 InitExpr = InitExpr->IgnoreParenCasts();
801 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
802 if (BO->isShiftOp() || BO->isBitwiseOp())
803 return true;
804
805 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
806 if (PowerOfTwo && EnumVal) {
807 if (!llvm::isPowerOf2_64(EnumVal))
808 PowerOfTwo = false;
809 else if (EnumVal > MaxPowerOfTwoVal)
810 MaxPowerOfTwoVal = EnumVal;
811 }
812 if (AllHexdecimalEnumerator && EnumVal) {
813 bool FoundHexdecimalEnumerator = false;
814 SourceLocation EndLoc = Enumerator->getEndLoc();
815 Token Tok;
816 if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
817 if (Tok.isLiteral() && Tok.getLength() > 2) {
818 if (const char *StringLit = Tok.getLiteralData())
819 FoundHexdecimalEnumerator =
820 (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
821 }
822 if (!FoundHexdecimalEnumerator)
823 AllHexdecimalEnumerator = false;
824 }
825 }
826 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
827}
828
829void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
830 const ObjCImplementationDecl *ImpDecl) {
831 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
832 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
833 return;
834 // Find all implicit conforming protocols for this class
835 // and make them explicit.
837 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
838 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
839
840 for (ObjCProtocolDecl *ProtDecl : ObjCProtocolDecls)
841 if (!ExplicitProtocols.count(ProtDecl))
842 PotentialImplicitProtocols.push_back(ProtDecl);
843
844 if (PotentialImplicitProtocols.empty())
845 return;
846
847 // go through list of non-optional methods and properties in each protocol
848 // in the PotentialImplicitProtocols list. If class implements every one of the
849 // methods and properties, then this class conforms to this protocol.
850 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
851 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
852 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
853 PotentialImplicitProtocols[i]))
854 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
855
856 if (ConformingProtocols.empty())
857 return;
858
859 // Further reduce number of conforming protocols. If protocol P1 is in the list
860 // protocol P2 (P2<P1>), No need to include P1.
861 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
862 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
863 bool DropIt = false;
864 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
865 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
866 ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
867 if (PDecl == TargetPDecl)
868 continue;
869 if (PDecl->lookupProtocolNamed(
870 TargetPDecl->getDeclName().getAsIdentifierInfo())) {
871 DropIt = true;
872 break;
873 }
874 }
875 if (!DropIt)
876 MinimalConformingProtocols.push_back(TargetPDecl);
877 }
878 if (MinimalConformingProtocols.empty())
879 return;
880 edit::Commit commit(*Editor);
881 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
882 *NSAPIObj, commit);
883 Editor->commit(commit);
884}
885
886void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
887 const TypedefDecl *TypedefDcl) {
888
889 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
890 if (NSAPIObj->isObjCNSIntegerType(qt))
891 NSIntegerTypedefed = TypedefDcl;
892 else if (NSAPIObj->isObjCNSUIntegerType(qt))
893 NSUIntegerTypedefed = TypedefDcl;
894}
895
896bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
897 const EnumDecl *EnumDcl,
898 const TypedefDecl *TypedefDcl) {
899 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
900 EnumDcl->isDeprecated())
901 return false;
902 if (!TypedefDcl) {
903 if (NSIntegerTypedefed) {
904 TypedefDcl = NSIntegerTypedefed;
905 NSIntegerTypedefed = nullptr;
906 }
907 else if (NSUIntegerTypedefed) {
908 TypedefDcl = NSUIntegerTypedefed;
909 NSUIntegerTypedefed = nullptr;
910 }
911 else
912 return false;
913 FileID FileIdOfTypedefDcl =
914 PP.getSourceManager().getFileID(TypedefDcl->getLocation());
915 FileID FileIdOfEnumDcl =
916 PP.getSourceManager().getFileID(EnumDcl->getLocation());
917 if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
918 return false;
919 }
920 if (TypedefDcl->isDeprecated())
921 return false;
922
923 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
924 StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt);
925
926 if (NSIntegerName.empty()) {
927 // Also check for typedef enum {...} TD;
928 if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
929 if (EnumTy->getDecl() == EnumDcl) {
930 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
931 if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
932 return false;
933 edit::Commit commit(*Editor);
934 rewriteToNSMacroDecl(Ctx, EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
935 Editor->commit(commit);
936 return true;
937 }
938 }
939 return false;
940 }
941
942 // We may still use NS_OPTIONS based on what we find in the enumertor list.
943 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
944 if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
945 return false;
946 edit::Commit commit(*Editor);
947 bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
948 commit, NSIntegerName, NSOptions);
949 Editor->commit(commit);
950 return Res;
951}
952
954 const ObjCMigrateASTConsumer &ASTC,
955 ObjCMethodDecl *OM) {
956 if (OM->getReturnType() == Ctx.getObjCInstanceType())
957 return; // already has instancetype.
958
959 SourceRange R;
960 std::string ClassString;
961 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
962 TypeLoc TL = TSInfo->getTypeLoc();
963 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
964 ClassString = "instancetype";
965 }
966 else {
967 R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
968 ClassString = OM->isInstanceMethod() ? '-' : '+';
969 ClassString += " (instancetype)";
970 }
971 edit::Commit commit(*ASTC.Editor);
972 commit.replace(R, ClassString);
973 ASTC.Editor->commit(commit);
974}
975
976static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
977 ObjCMethodDecl *OM) {
979 SourceRange R;
980 std::string ClassString;
981 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
982 TypeLoc TL = TSInfo->getTypeLoc();
983 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
984 ClassString = std::string(IDecl->getName());
985 ClassString += "*";
986 }
987 }
988 else {
989 R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
990 ClassString = "+ (";
991 ClassString += IDecl->getName(); ClassString += "*)";
992 }
993 edit::Commit commit(*ASTC.Editor);
994 commit.replace(R, ClassString);
995 ASTC.Editor->commit(commit);
996}
997
998void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
999 ObjCContainerDecl *CDecl,
1000 ObjCMethodDecl *OM) {
1001 ObjCInstanceTypeFamily OIT_Family =
1003
1004 std::string ClassName;
1005 switch (OIT_Family) {
1006 case OIT_None:
1007 migrateFactoryMethod(Ctx, CDecl, OM);
1008 return;
1009 case OIT_Array:
1010 ClassName = "NSArray";
1011 break;
1012 case OIT_Dictionary:
1013 ClassName = "NSDictionary";
1014 break;
1015 case OIT_Singleton:
1016 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
1017 return;
1018 case OIT_Init:
1019 if (OM->getReturnType()->isObjCIdType())
1020 ReplaceWithInstancetype(Ctx, *this, OM);
1021 return;
1022 case OIT_ReturnsSelf:
1023 migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
1024 return;
1025 }
1026 if (!OM->getReturnType()->isObjCIdType())
1027 return;
1028
1029 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1030 if (!IDecl) {
1031 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1032 IDecl = CatDecl->getClassInterface();
1033 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1034 IDecl = ImpDecl->getClassInterface();
1035 }
1036 if (!IDecl ||
1037 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
1038 migrateFactoryMethod(Ctx, CDecl, OM);
1039 return;
1040 }
1041 ReplaceWithInstancetype(Ctx, *this, OM);
1042}
1043
1045 if (!T->isAnyPointerType())
1046 return false;
1050 return false;
1051 // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
1052 // is not an innter pointer type.
1053 QualType OrigT = T;
1054 while (const auto *TD = T->getAs<TypedefType>())
1055 T = TD->getDecl()->getUnderlyingType();
1056 if (OrigT == T || !T->isPointerType())
1057 return true;
1058 const PointerType* PT = T->getAs<PointerType>();
1059 QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
1060 if (UPointeeT->isRecordType()) {
1061 const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
1062 if (!RecordTy->getDecl()->isCompleteDefinition())
1063 return false;
1064 }
1065 return true;
1066}
1067
1068/// Check whether the two versions match.
1069static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) {
1070 return (X == Y);
1071}
1072
1073/// AvailabilityAttrsMatch - This routine checks that if comparing two
1074/// availability attributes, all their components match. It returns
1075/// true, if not dealing with availability or when all components of
1076/// availability attributes match. This routine is only called when
1077/// the attributes are of the same kind.
1078static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
1079 const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
1080 if (!AA1)
1081 return true;
1082 const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2);
1083
1084 VersionTuple Introduced1 = AA1->getIntroduced();
1085 VersionTuple Deprecated1 = AA1->getDeprecated();
1086 VersionTuple Obsoleted1 = AA1->getObsoleted();
1087 bool IsUnavailable1 = AA1->getUnavailable();
1088 VersionTuple Introduced2 = AA2->getIntroduced();
1089 VersionTuple Deprecated2 = AA2->getDeprecated();
1090 VersionTuple Obsoleted2 = AA2->getObsoleted();
1091 bool IsUnavailable2 = AA2->getUnavailable();
1092 return (versionsMatch(Introduced1, Introduced2) &&
1093 versionsMatch(Deprecated1, Deprecated2) &&
1094 versionsMatch(Obsoleted1, Obsoleted2) &&
1095 IsUnavailable1 == IsUnavailable2);
1096}
1097
1098static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2,
1099 bool &AvailabilityArgsMatch) {
1100 // This list is very small, so this need not be optimized.
1101 for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
1102 bool match = false;
1103 for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
1104 // Matching attribute kind only. Except for Availability attributes,
1105 // we are not getting into details of the attributes. For all practical purposes
1106 // this is sufficient.
1107 if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
1108 if (AvailabilityArgsMatch)
1109 AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]);
1110 match = true;
1111 break;
1112 }
1113 }
1114 if (!match)
1115 return false;
1116 }
1117 return true;
1118}
1119
1120/// AttributesMatch - This routine checks list of attributes for two
1121/// decls. It returns false, if there is a mismatch in kind of
1122/// attributes seen in the decls. It returns true if the two decls
1123/// have list of same kind of attributes. Furthermore, when there
1124/// are availability attributes in the two decls, it sets the
1125/// AvailabilityArgsMatch to false if availability attributes have
1126/// different versions, etc.
1127static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2,
1128 bool &AvailabilityArgsMatch) {
1129 if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) {
1130 AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs());
1131 return true;
1132 }
1133 AvailabilityArgsMatch = true;
1134 const AttrVec &Attrs1 = Decl1->getAttrs();
1135 const AttrVec &Attrs2 = Decl2->getAttrs();
1136 bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch);
1137 if (match && (Attrs2.size() > Attrs1.size()))
1138 return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch);
1139 return match;
1140}
1141
1143 const char *Name) {
1144 if (!isAsciiIdentifierStart(Name[0]))
1145 return false;
1146 std::string NameString = Name;
1147 NameString[0] = toLowercase(NameString[0]);
1148 const IdentifierInfo *II = &Ctx.Idents.get(NameString);
1149 return II->getTokenID() == tok::identifier;
1150}
1151
1152bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
1154 ObjCMethodDecl *Method) {
1155 if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
1156 Method->param_size() != 0)
1157 return false;
1158 // Is this method candidate to be a getter?
1159 QualType GRT = Method->getReturnType();
1160 if (GRT->isVoidType())
1161 return false;
1162
1163 Selector GetterSelector = Method->getSelector();
1164 ObjCInstanceTypeFamily OIT_Family =
1165 Selector::getInstTypeMethodFamily(GetterSelector);
1166
1167 if (OIT_Family != OIT_None)
1168 return false;
1169
1170 const IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
1171 Selector SetterSelector =
1173 PP.getSelectorTable(),
1174 getterName);
1175 ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
1176 unsigned LengthOfPrefix = 0;
1177 if (!SetterMethod) {
1178 // try a different naming convention for getter: isXxxxx
1179 StringRef getterNameString = getterName->getName();
1180 bool IsPrefix = getterNameString.starts_with("is");
1181 // Note that we don't want to change an isXXX method of retainable object
1182 // type to property (readonly or otherwise).
1183 if (IsPrefix && GRT->isObjCRetainableType())
1184 return false;
1185 if (IsPrefix || getterNameString.starts_with("get")) {
1186 LengthOfPrefix = (IsPrefix ? 2 : 3);
1187 const char *CGetterName = getterNameString.data() + LengthOfPrefix;
1188 // Make sure that first character after "is" or "get" prefix can
1189 // start an identifier.
1190 if (!IsValidIdentifier(Ctx, CGetterName))
1191 return false;
1192 if (CGetterName[0] && isUppercase(CGetterName[0])) {
1193 getterName = &Ctx.Idents.get(CGetterName);
1194 SetterSelector =
1196 PP.getSelectorTable(),
1197 getterName);
1198 SetterMethod = D->getInstanceMethod(SetterSelector);
1199 }
1200 }
1201 }
1202
1203 if (SetterMethod) {
1204 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
1205 return false;
1206 bool AvailabilityArgsMatch;
1207 if (SetterMethod->isDeprecated() ||
1208 !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch))
1209 return false;
1210
1211 // Is this a valid setter, matching the target getter?
1212 QualType SRT = SetterMethod->getReturnType();
1213 if (!SRT->isVoidType())
1214 return false;
1215 const ParmVarDecl *argDecl = *SetterMethod->param_begin();
1216 QualType ArgType = argDecl->getType();
1217 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
1218 return false;
1219 edit::Commit commit(*Editor);
1220 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
1221 LengthOfPrefix,
1222 (ASTMigrateActions &
1224 (ASTMigrateActions &
1226 AvailabilityArgsMatch);
1227 Editor->commit(commit);
1228 return true;
1229 }
1230 else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
1231 // Try a non-void method with no argument (and no setter or property of same name
1232 // as a 'readonly' property.
1233 edit::Commit commit(*Editor);
1234 rewriteToObjCProperty(Method, nullptr /*SetterMethod*/, *NSAPIObj, commit,
1235 LengthOfPrefix,
1236 (ASTMigrateActions &
1238 (ASTMigrateActions &
1240 /*AvailabilityArgsMatch*/false);
1241 Editor->commit(commit);
1242 return true;
1243 }
1244 return false;
1245}
1246
1247void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
1248 ObjCMethodDecl *OM) {
1249 if (OM->isImplicit() ||
1250 !OM->isInstanceMethod() ||
1251 OM->hasAttr<ObjCReturnsInnerPointerAttr>())
1252 return;
1253
1254 QualType RT = OM->getReturnType();
1255 if (!TypeIsInnerPointer(RT) ||
1256 !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
1257 return;
1258
1259 edit::Commit commit(*Editor);
1260 commit.insertBefore(OM->getEndLoc(), " NS_RETURNS_INNER_POINTER");
1261 Editor->commit(commit);
1262}
1263
1264void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
1266 QualType T = P->getType();
1267
1268 if (!TypeIsInnerPointer(T) ||
1269 !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
1270 return;
1271 edit::Commit commit(*Editor);
1272 commit.insertBefore(P->getEndLoc(), " NS_RETURNS_INNER_POINTER ");
1273 Editor->commit(commit);
1274}
1275
1276void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
1277 ObjCContainerDecl *CDecl) {
1278 if (CDecl->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(CDecl))
1279 return;
1280
1281 // migrate methods which can have instancetype as their result type.
1282 for (auto *Method : CDecl->methods()) {
1283 if (Method->isDeprecated())
1284 continue;
1285 migrateMethodInstanceType(Ctx, CDecl, Method);
1286 }
1287}
1288
1289void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
1290 ObjCContainerDecl *CDecl,
1291 ObjCMethodDecl *OM,
1292 ObjCInstanceTypeFamily OIT_Family) {
1293 if (OM->isInstanceMethod() ||
1294 OM->getReturnType() == Ctx.getObjCInstanceType() ||
1295 !OM->getReturnType()->isObjCIdType())
1296 return;
1297
1298 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
1299 // NSYYYNamE with matching names be at least 3 characters long.
1300 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1301 if (!IDecl) {
1302 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1303 IDecl = CatDecl->getClassInterface();
1304 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1305 IDecl = ImpDecl->getClassInterface();
1306 }
1307 if (!IDecl)
1308 return;
1309
1310 std::string StringClassName = std::string(IDecl->getName());
1311 StringRef LoweredClassName(StringClassName);
1312 std::string StringLoweredClassName = LoweredClassName.lower();
1313 LoweredClassName = StringLoweredClassName;
1314
1315 const IdentifierInfo *MethodIdName =
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.starts_with("standard"))
1326 len = strlen("standard");
1327 else if (STRefMethodName.starts_with("shared"))
1328 len = strlen("shared");
1329 else if (STRefMethodName.starts_with("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.starts_with(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) {
1681 if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
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());
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(newText.str(), file->getName()));
1968 SmallString<64> filePath(file->getName());
1969 FileMgr.FixupRelativePath(filePath);
1970 Remapper.remap(filePath.str(), std::move(memBuf));
1971 }
1972
1973 if (IsOutputFile) {
1974 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
1975 } else {
1976 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
1977 }
1978}
1979
1982 return true;
1983}
1984
1985static std::vector<std::string> getAllowListFilenames(StringRef DirPath) {
1986 using namespace llvm::sys::fs;
1987 using namespace llvm::sys::path;
1988
1989 std::vector<std::string> Filenames;
1990 if (DirPath.empty() || !is_directory(DirPath))
1991 return Filenames;
1992
1993 std::error_code EC;
1994 directory_iterator DI = directory_iterator(DirPath, EC);
1995 directory_iterator DE;
1996 for (; !EC && DI != DE; DI = DI.increment(EC)) {
1997 if (is_regular_file(DI->path()))
1998 Filenames.push_back(std::string(filename(DI->path())));
1999 }
2000
2001 return Filenames;
2002}
2003
2004std::unique_ptr<ASTConsumer>
2008 unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
2009 unsigned ObjCMTOpts = ObjCMTAction;
2010 // These are companion flags, they do not enable transformations.
2013 if (ObjCMTOpts == FrontendOptions::ObjCMT_None) {
2014 // If no specific option was given, enable literals+subscripting transforms
2015 // by default.
2016 ObjCMTAction |=
2018 }
2019 CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
2020 std::vector<std::string> AllowList =
2022 return std::make_unique<ObjCMigrateASTConsumer>(
2023 CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper,
2024 CI.getFileManager(), PPRec, CI.getPreprocessor(),
2025 /*isOutputFile=*/true, AllowList);
2026}
2027
2028namespace {
2029struct EditEntry {
2031 unsigned Offset = 0;
2032 unsigned RemoveLen = 0;
2033 std::string Text;
2034};
2035} // end anonymous namespace
2036
2037namespace llvm {
2038template<> struct DenseMapInfo<EditEntry> {
2039 static inline EditEntry getEmptyKey() {
2040 EditEntry Entry;
2041 Entry.Offset = unsigned(-1);
2042 return Entry;
2043 }
2044 static inline EditEntry getTombstoneKey() {
2045 EditEntry Entry;
2046 Entry.Offset = unsigned(-2);
2047 return Entry;
2048 }
2049 static unsigned getHashValue(const EditEntry& Val) {
2050 return (unsigned)llvm::hash_combine(Val.File, Val.Offset, Val.RemoveLen,
2051 Val.Text);
2052 }
2053 static bool isEqual(const EditEntry &LHS, const EditEntry &RHS) {
2054 return LHS.File == RHS.File &&
2055 LHS.Offset == RHS.Offset &&
2056 LHS.RemoveLen == RHS.RemoveLen &&
2057 LHS.Text == RHS.Text;
2058 }
2059};
2060} // end namespace llvm
2061
2062namespace {
2063class RemapFileParser {
2064 FileManager &FileMgr;
2065
2066public:
2067 RemapFileParser(FileManager &FileMgr) : FileMgr(FileMgr) { }
2068
2069 bool parse(StringRef File, SmallVectorImpl<EditEntry> &Entries) {
2070 using namespace llvm::yaml;
2071
2072 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
2073 llvm::MemoryBuffer::getFile(File);
2074 if (!FileBufOrErr)
2075 return true;
2076
2077 llvm::SourceMgr SM;
2078 Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(), SM);
2079 document_iterator I = YAMLStream.begin();
2080 if (I == YAMLStream.end())
2081 return true;
2082 Node *Root = I->getRoot();
2083 if (!Root)
2084 return true;
2085
2086 SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root);
2087 if (!SeqNode)
2088 return true;
2089
2090 for (SequenceNode::iterator
2091 AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) {
2092 MappingNode *MapNode = dyn_cast<MappingNode>(&*AI);
2093 if (!MapNode)
2094 continue;
2095 parseEdit(MapNode, Entries);
2096 }
2097
2098 return false;
2099 }
2100
2101private:
2102 void parseEdit(llvm::yaml::MappingNode *Node,
2103 SmallVectorImpl<EditEntry> &Entries) {
2104 using namespace llvm::yaml;
2105 EditEntry Entry;
2106 bool Ignore = false;
2107
2108 for (MappingNode::iterator
2109 KVI = Node->begin(), KVE = Node->end(); KVI != KVE; ++KVI) {
2110 ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey());
2111 if (!KeyString)
2112 continue;
2113 SmallString<10> KeyStorage;
2114 StringRef Key = KeyString->getValue(KeyStorage);
2115
2116 ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue());
2117 if (!ValueString)
2118 continue;
2119 SmallString<64> ValueStorage;
2120 StringRef Val = ValueString->getValue(ValueStorage);
2121
2122 if (Key == "file") {
2123 if (auto File = FileMgr.getOptionalFileRef(Val))
2124 Entry.File = File;
2125 else
2126 Ignore = true;
2127 } else if (Key == "offset") {
2128 if (Val.getAsInteger(10, Entry.Offset))
2129 Ignore = true;
2130 } else if (Key == "remove") {
2131 if (Val.getAsInteger(10, Entry.RemoveLen))
2132 Ignore = true;
2133 } else if (Key == "text") {
2134 Entry.Text = std::string(Val);
2135 }
2136 }
2137
2138 if (!Ignore)
2139 Entries.push_back(Entry);
2140 }
2141};
2142} // end anonymous namespace
2143
2144static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) {
2145 Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
2146 << Err.str();
2147 return true;
2148}
2149
2150static std::string applyEditsToTemp(FileEntryRef FE,
2151 ArrayRef<EditEntry> Edits,
2152 FileManager &FileMgr,
2154 using namespace llvm::sys;
2155
2156 SourceManager SM(Diag, FileMgr);
2157 FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
2158 LangOptions LangOpts;
2159 edit::EditedSource Editor(SM, LangOpts);
2161 I = Edits.begin(), E = Edits.end(); I != E; ++I) {
2162 const EditEntry &Entry = *I;
2163 assert(Entry.File == FE);
2165 SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset);
2167 if (Entry.RemoveLen != 0) {
2169 Loc.getLocWithOffset(Entry.RemoveLen));
2170 }
2171
2172 edit::Commit commit(Editor);
2173 if (Range.isInvalid()) {
2174 commit.insert(Loc, Entry.Text);
2175 } else if (Entry.Text.empty()) {
2176 commit.remove(Range);
2177 } else {
2178 commit.replace(Range, Entry.Text);
2179 }
2180 Editor.commit(commit);
2181 }
2182
2183 Rewriter rewriter(SM, LangOpts);
2184 RewritesReceiver Rec(rewriter);
2185 Editor.applyRewrites(Rec, /*adjustRemovals=*/false);
2186
2187 const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
2188 SmallString<512> NewText;
2189 llvm::raw_svector_ostream OS(NewText);
2190 Buf->write(OS);
2191
2192 SmallString<64> TempPath;
2193 int FD;
2194 if (fs::createTemporaryFile(path::filename(FE.getName()),
2195 path::extension(FE.getName()).drop_front(), FD,
2196 TempPath)) {
2197 reportDiag("Could not create file: " + TempPath.str(), Diag);
2198 return std::string();
2199 }
2200
2201 llvm::raw_fd_ostream TmpOut(FD, /*shouldClose=*/true);
2202 TmpOut.write(NewText.data(), NewText.size());
2203 TmpOut.close();
2204
2205 return std::string(TempPath);
2206}
2207
2209 std::vector<std::pair<std::string,std::string> > &remap,
2210 ArrayRef<StringRef> remapFiles,
2211 DiagnosticConsumer *DiagClient) {
2212 bool hasErrorOccurred = false;
2213
2214 FileSystemOptions FSOpts;
2215 FileManager FileMgr(FSOpts);
2216 RemapFileParser Parser(FileMgr);
2217
2220 new DiagnosticsEngine(DiagID, new DiagnosticOptions,
2221 DiagClient, /*ShouldOwnClient=*/false));
2222
2223 typedef llvm::DenseMap<FileEntryRef, std::vector<EditEntry> >
2224 FileEditEntriesTy;
2225 FileEditEntriesTy FileEditEntries;
2226
2227 llvm::DenseSet<EditEntry> EntriesSet;
2228
2230 I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
2232 if (Parser.parse(*I, Entries))
2233 continue;
2234
2236 EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) {
2237 EditEntry &Entry = *EI;
2238 if (!Entry.File)
2239 continue;
2240 std::pair<llvm::DenseSet<EditEntry>::iterator, bool>
2241 Insert = EntriesSet.insert(Entry);
2242 if (!Insert.second)
2243 continue;
2244
2245 FileEditEntries[*Entry.File].push_back(Entry);
2246 }
2247 }
2248
2249 for (FileEditEntriesTy::iterator
2250 I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) {
2251 std::string TempFile = applyEditsToTemp(I->first, I->second,
2252 FileMgr, *Diags);
2253 if (TempFile.empty()) {
2254 hasErrorOccurred = true;
2255 continue;
2256 }
2257
2258 remap.emplace_back(std::string(I->first.getName()), TempFile);
2259 }
2260
2261 return hasErrorOccurred;
2262}
Defines the clang::ASTContext interface.
DynTypedNode Node
StringRef P
#define SM(sm)
Definition: Cuda.cpp:83
const Decl * D
IndirectLocalPath & Path
Expr * E
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:1171
Defines the clang::FileManager interface and associated types.
StringRef Text
Definition: Format.cpp:3002
#define X(type, name)
Definition: Value.h:143
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:660
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:1142
static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag)
Definition: ObjCMT.cpp:2144
static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2)
AvailabilityAttrsMatch - This routine checks that if comparing two availability attributes,...
Definition: ObjCMT.cpp:1078
static const char * PropertyMemoryAttribute(ASTContext &Context, QualType ArgType)
Definition: ObjCMT.cpp:427
static void ReplaceWithInstancetype(ASTContext &Ctx, const ObjCMigrateASTConsumer &ASTC, ObjCMethodDecl *OM)
Definition: ObjCMT.cpp:953
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:453
static bool TypeIsInnerPointer(QualType T)
Definition: ObjCMT.cpp:1044
static StringRef GetUnsignedName(StringRef NSIntegerName)
Definition: ObjCMT.cpp:692
static bool hasSuperInitCall(const ObjCMethodDecl *MD)
Definition: ObjCMT.cpp:1690
static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D)
Definition: ObjCMT.cpp:563
static std::string applyEditsToTemp(FileEntryRef FE, ArrayRef< EditEntry > Edits, FileManager &FileMgr, DiagnosticsEngine &Diag)
Definition: ObjCMT.cpp:2150
static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y)
Check whether the two versions match.
Definition: ObjCMT.cpp:1069
static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2, bool &AvailabilityArgsMatch)
AttributesMatch - This routine checks list of attributes for two decls.
Definition: ObjCMT.cpp:1127
static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, StringRef NSIntegerName, bool NSOptions)
Definition: ObjCMT.cpp:703
static void rewriteToNSMacroDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, bool IsNSIntegerType)
Definition: ObjCMT.cpp:757
static bool ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, const ObjCImplementationDecl *ImpDecl, const ObjCInterfaceDecl *IDecl, ObjCProtocolDecl *Protocol)
Definition: ObjCMT.cpp:599
static void append_attr(std::string &PropertyString, const char *attr, bool &LParenAdded)
Definition: ObjCMT.cpp:384
static void MigrateBlockOrFunctionPointerTypeVariable(std::string &PropertyString, const std::string &TypeString, const char *name)
Definition: ObjCMT.cpp:396
static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC, ObjCMethodDecl *OM)
Definition: ObjCMT.cpp:976
static std::vector< std::string > getAllowListFilenames(StringRef DirPath)
Definition: ObjCMT.cpp:1985
static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, const EnumDecl *EnumDcl)
Definition: ObjCMT.cpp:788
static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2, bool &AvailabilityArgsMatch)
Definition: ObjCMT.cpp:1098
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:34
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: ASTConsumer.h:67
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:48
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:187
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, const ObjCMethodDecl *MethodImp)
SourceManager & getSourceManager()
Definition: ASTContext.h:721
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1101
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2628
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
Definition: ASTContext.h:2644
IdentifierTable & Idents
Definition: ASTContext.h:660
const LangOptions & getLangOpts() const
Definition: ASTContext.h:797
QualType getObjCInstanceType()
Retrieve the Objective-C "instancetype" type, if already known; otherwise, returns a NULL type;.
Definition: ASTContext.h:1998
QualType getQualifiedType(SplitQualType split) const
Un-split a SplitQualType.
Definition: ASTContext.h:2210
const clang::PrintingPolicy & getPrintingPolicy() const
Definition: ASTContext.h:713
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2675
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:42
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3860
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:1369
decl_iterator - Iterates through the declarations stored within this context.
Definition: DeclBase.h:2307
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1852
decl_iterator decls_end() const
Definition: DeclBase.h:2352
decl_iterator decls_begin() const
Definition: DeclBase.cpp:1622
iterator begin()
Definition: DeclGroup.h:99
iterator end()
Definition: DeclGroup.h:105
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
SourceLocation getEndLoc() const LLVM_READONLY
Definition: DeclBase.h:442
bool hasAttrs() const
Definition: DeclBase.h:525
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:600
SourceLocation getLocation() const
Definition: DeclBase.h:446
bool isDeprecated(std::string *Message=nullptr) const
Determine whether this declaration is marked 'deprecated'.
Definition: DeclBase.h:756
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: DeclBase.h:438
AttrVec & getAttrs()
Definition: DeclBase.h:531
bool hasAttr() const
Definition: DeclBase.h:584
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:1745
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:1547
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
Definition: Diagnostic.h:873
void setIgnoreAllWarnings(bool Val)
When set to true, any unmapped warnings are ignored.
Definition: Diagnostic.h:650
Represents an enum.
Definition: Decl.h:3844
enumerator_range enumerators() const
Definition: Decl.h:3977
QualType getIntegerType() const
Return the integer type this enum decl corresponds to.
Definition: Decl.h:4004
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of enums.
Definition: Type.h:5991
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:3075
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3050
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:240
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:1044
Represents a function declaration or definition.
Definition: Decl.h:1932
param_iterator param_end()
Definition: Decl.h:2659
QualType getReturnType() const
Definition: Decl.h:2717
param_iterator param_begin()
Definition: Decl.h:2658
ArrayRef< ParmVarDecl * >::const_iterator param_const_iterator
Definition: Decl.h:2655
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:3678
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3144
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:476
bool isMacroDefined(StringRef Id) const
Returns true if Id is currently defined as a macro.
Definition: NSAPI.cpp:519
ASTContext & getASTContext() const
Definition: NSAPI.h:27
This represents a decl that may have a name.
Definition: Decl.h:249
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:315
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:292
ObjCCategoryDecl - Represents a category declaration.
Definition: DeclObjC.h:2328
ObjCCategoryImplDecl - An object of this class encapsulates a category @implementation declaration.
Definition: DeclObjC.h:2544
ObjCContainerDecl - Represents a container for method declarations.
Definition: DeclObjC.h:947
ObjCMethodDecl * getMethod(Selector Sel, bool isInstance, bool AllowHidden=false) const
Definition: DeclObjC.cpp:93
method_range methods() const
Definition: DeclObjC.h:1015
instmeth_range instance_methods() const
Definition: DeclObjC.h:1032
ObjCPropertyImplDecl * FindPropertyImplDecl(IdentifierInfo *propertyId, ObjCPropertyQueryKind queryKind) const
FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl added to the list of thos...
Definition: DeclObjC.cpp:2245
const ObjCInterfaceDecl * getClassInterface() const
Definition: DeclObjC.h:2485
ObjCImplementationDecl - Represents a class definition - this is where method definitions are specifi...
Definition: DeclObjC.h:2596
Represents an ObjC class declaration.
Definition: DeclObjC.h:1153
ObjCInterfaceDecl * lookupInheritedClass(const IdentifierInfo *ICName)
lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super class whose name is passe...
Definition: DeclObjC.cpp:668
protocol_loc_iterator protocol_loc_end() const
Definition: DeclObjC.h:1402
SourceLocation getSuperClassLoc() const
Retrieve the starting location of the superclass.
Definition: DeclObjC.cpp:372
const ObjCProtocolList & getReferencedProtocols() const
Definition: DeclObjC.h:1332
ObjCProtocolDecl * lookupNestedProtocol(IdentifierInfo *Name)
Definition: DeclObjC.cpp:687
bool hasDesignatedInitializers() const
Returns true if this interface decl contains at least one initializer marked with the 'objc_designate...
Definition: DeclObjC.cpp:1602
ObjCInterfaceDecl * getSuperClass() const
Definition: DeclObjC.cpp:352
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:945
bool isImplicit() const
Indicates whether the message send was implicitly generated by the implementation.
Definition: ExprObjC.h:1230
Expr ** getArgs()
Retrieve the arguments to this message, not including the receiver.
Definition: ExprObjC.h:1386
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1260
SourceLocation getSuperLoc() const
Retrieve the location of the 'super' keyword for a class or instance message to 'super',...
Definition: ExprObjC.h:1301
@ SuperInstance
The receiver is the instance of the superclass object.
Definition: ExprObjC.h:959
@ Instance
The receiver is an object instance.
Definition: ExprObjC.h:953
const ObjCMethodDecl * getMethodDecl() const
Definition: ExprObjC.h:1356
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
Definition: ExprObjC.h:1234
SourceLocation getSelectorLoc(unsigned Index) const
Definition: ExprObjC.h:1425
unsigned getNumArgs() const
Return the number of actual arguments in this message, not counting the receiver.
Definition: ExprObjC.h:1382
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:140
bool hasBody() const override
Determine whether this method has a body.
Definition: DeclObjC.h:523
unsigned param_size() const
Definition: DeclObjC.h:347
bool isPropertyAccessor() const
Definition: DeclObjC.h:436
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:358
SourceLocation getSelectorStartLoc() const
Definition: DeclObjC.h:288
param_const_iterator param_begin() const
Definition: DeclObjC.h:354
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:343
const ParmVarDecl *const * param_const_iterator
Definition: DeclObjC.h:349
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: DeclObjC.h:282
Selector getSelector() const
Definition: DeclObjC.h:327
bool isInstanceMethod() const
Definition: DeclObjC.h:426
ObjCMethodFamily getMethodFamily() const
Determines the family of this method.
Definition: DeclObjC.cpp:1053
QualType getReturnType() const
Definition: DeclObjC.h:329
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1211
SourceLocation getDeclaratorEndLoc() const
Returns the location where the declarator ends.
Definition: DeclObjC.h:279
Represents a pointer to an Objective C object.
Definition: Type.h:7399
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:730
Represents an Objective-C protocol declaration.
Definition: DeclObjC.h:2083
ObjCProtocolDecl * lookupProtocolNamed(IdentifierInfo *PName)
Definition: DeclObjC.cpp:1982
ObjCProtocolDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this Objective-C protocol.
Definition: DeclObjC.h:2296
Records preprocessor conditional directive regions and allows querying in which region source locatio...
Represents a parameter to a function.
Definition: Decl.h:1722
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:58
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:3187
QualType getPointeeType() const
Definition: Type.h:3197
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:137
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:941
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:1008
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition: Type.h:7790
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition: Type.h:1444
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:7844
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: Type.h:1339
The collection of all-type qualifiers we support.
Definition: Type.h:319
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition: Type.h:348
@ OCL_None
There is no lifetime qualification on this type.
Definition: Type.h:337
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition: Type.h:351
void removeObjCLifetime()
Definition: Type.h:538
bool hasObjCLifetime() const
Definition: Type.h:531
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:5965
RecordDecl * getDecl() const
Definition: Type.h:5975
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Rewriter - This is the main interface to the rewrite buffers.
Definition: Rewriter.h:32
std::map< FileID, llvm::RewriteBuffer >::iterator buffer_iterator
Definition: Rewriter.h:65
const llvm::RewriteBuffer * getRewriteBufferFor(FileID FID) const
getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
Definition: Rewriter.h:199
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.
const 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:84
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Stmt.cpp:350
child_range children()
Definition: Stmt.cpp:287
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:338
SourceRange getBraceRange() const
Definition: Decl.h:3640
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Definition: Decl.h:3664
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
bool isLiteral() const
Return true if this is a "literal", like a numeric constant, string, etc.
Definition: Token.h:116
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:132
unsigned getLength() const
Definition: Token.h:135
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
Definition: Token.h:225
The top declaration context.
Definition: Decl.h:84
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Decl.h:3394
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:7721
QualType getType() const
Return the type wrapped by this type source info.
Definition: Type.h:7732
bool isBlockPointerType() const
Definition: Type.h:8017
bool isVoidType() const
Definition: Type.h:8319
bool isObjCBuiltinType() const
Definition: Type.h:8196
bool isFunctionPointerType() const
Definition: Type.h:8043
bool isPointerType() const
Definition: Type.h:8003
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:8607
bool isObjCIdType() const
Definition: Type.h:8178
bool isObjCObjectPointerType() const
Definition: Type.h:8145
bool isAnyPointerType() const
Definition: Type.h:8011
bool isRealType() const
Definition: Type.cpp:2272
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8540
bool isObjCRetainableType() const
Definition: Type.cpp:4950
Represents the declaration of a typedef-name via the 'typedef' type specifier.
Definition: Decl.h:3511
TypeSourceInfo * getTypeSourceInfo() const
Definition: Decl.h:3459
QualType getType() const
Definition: Decl.h:678
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:2005
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
Definition: ObjCMT.cpp:1980
bool BeginInvocation(CompilerInstance &CI) override
Callback before starting processing a single input, giving the opportunity to modify the CompilerInvo...
Definition: ObjCMT.cpp:207
ObjCMigrateAction(std::unique_ptr< FrontendAction > WrappedAction, StringRef migrateDir, unsigned migrateAction)
Definition: ObjCMT.cpp:185
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
Definition: ObjCMT.cpp:195
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:117
SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx, bool IsDecl=false)
'Loc' is the end of a statement range.
Definition: Transforms.cpp:129
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:2208
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:275
RangeSelector range(RangeSelector Begin, RangeSelector End)
DEPRECATED. Use enclose.
Definition: RangeSelector.h:41
ASTEdit remove(RangeSelector S)
Removes the source selected by S.
The JSON file list parser is used to communicate input to InstallAPI.
@ 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:224
LLVM_READONLY bool isUppercase(unsigned char c)
Return true if this character is an uppercase ASCII letter: [A-Z].
Definition: CharInfo.h:126
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
const FunctionProtoType * T
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:53
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
#define false
Definition: stdbool.h:26
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:2053
static EditEntry getTombstoneKey()
Definition: ObjCMT.cpp:2044
static unsigned getHashValue(const EditEntry &Val)
Definition: ObjCMT.cpp:2049
static EditEntry getEmptyKey()
Definition: ObjCMT.cpp:2039