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