clang 19.0.0git
RewriteObjCFoundationAPI.cpp
Go to the documentation of this file.
1//===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
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// Rewrites legacy method calls to modern syntax.
10//
11//===----------------------------------------------------------------------===//
12
15#include "clang/AST/ExprCXX.h"
16#include "clang/AST/ExprObjC.h"
17#include "clang/AST/NSAPI.h"
18#include "clang/AST/ParentMap.h"
19#include "clang/Edit/Commit.h"
20#include "clang/Lex/Lexer.h"
21#include <optional>
22
23using namespace clang;
24using namespace edit;
25
27 IdentifierInfo *&ClassId,
28 const LangOptions &LangOpts) {
29 if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
30 return false;
31
32 const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
33 if (!Receiver)
34 return false;
35 ClassId = Receiver->getIdentifier();
36
38 return true;
39
40 // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
41 // since the change from +1 to +0 will be handled fine by ARC.
42 if (LangOpts.ObjCAutoRefCount) {
44 if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
46 if (Rec->getMethodFamily() == OMF_alloc)
47 return true;
48 }
49 }
50 }
51
52 return false;
53}
54
55//===----------------------------------------------------------------------===//
56// rewriteObjCRedundantCallWithLiteral.
57//===----------------------------------------------------------------------===//
58
60 const NSAPI &NS, Commit &commit) {
61 IdentifierInfo *II = nullptr;
63 return false;
64 if (Msg->getNumArgs() != 1)
65 return false;
66
67 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
68 Selector Sel = Msg->getSelector();
69
70 if ((isa<ObjCStringLiteral>(Arg) &&
74
75 (isa<ObjCArrayLiteral>(Arg) &&
79
80 (isa<ObjCDictionaryLiteral>(Arg) &&
85
86 commit.replaceWithInner(Msg->getSourceRange(),
87 Msg->getArg(0)->getSourceRange());
88 return true;
89 }
90
91 return false;
92}
93
94//===----------------------------------------------------------------------===//
95// rewriteToObjCSubscriptSyntax.
96//===----------------------------------------------------------------------===//
97
98/// Check for classes that accept 'objectForKey:' (or the other selectors
99/// that the migrator handles) but return their instances as 'id', resulting
100/// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
101///
102/// When checking if we can convert to subscripting syntax, check whether
103/// the receiver is a result of a class method from a hardcoded list of
104/// such classes. In such a case return the specific class as the interface
105/// of the receiver.
106///
107/// FIXME: Remove this when these classes start using 'instancetype'.
108static const ObjCInterfaceDecl *
110 const Expr *Receiver,
111 ASTContext &Ctx) {
112 assert(IFace && Receiver);
113
114 // If the receiver has type 'id'...
115 if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
116 return IFace;
117
118 const ObjCMessageExpr *
119 InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
120 if (!InnerMsg)
121 return IFace;
122
123 QualType ClassRec;
124 switch (InnerMsg->getReceiverKind()) {
127 return IFace;
128
130 ClassRec = InnerMsg->getClassReceiver();
131 break;
133 ClassRec = InnerMsg->getSuperType();
134 break;
135 }
136
137 if (ClassRec.isNull())
138 return IFace;
139
140 // ...and it is the result of a class message...
141
142 const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
143 if (!ObjTy)
144 return IFace;
145 const ObjCInterfaceDecl *OID = ObjTy->getInterface();
146
147 // ...and the receiving class is NSMapTable or NSLocale, return that
148 // class as the receiving interface.
149 if (OID->getName() == "NSMapTable" ||
150 OID->getName() == "NSLocale")
151 return OID;
152
153 return IFace;
154}
155
157 const ObjCMessageExpr *Msg,
158 ASTContext &Ctx,
159 Selector subscriptSel) {
160 const Expr *Rec = Msg->getInstanceReceiver();
161 if (!Rec)
162 return false;
163 IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
164
165 if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
166 if (!MD->isUnavailable())
167 return true;
168 }
169 return false;
170}
171
172static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
173
174static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
175 if (subscriptOperatorNeedsParens(Receiver)) {
176 SourceRange RecRange = Receiver->getSourceRange();
177 commit.insertWrap("(", RecRange, ")");
178 }
179}
180
182 Commit &commit) {
183 if (Msg->getNumArgs() != 1)
184 return false;
185 const Expr *Rec = Msg->getInstanceReceiver();
186 if (!Rec)
187 return false;
188
189 SourceRange MsgRange = Msg->getSourceRange();
190 SourceRange RecRange = Rec->getSourceRange();
191 SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
192
194 ArgRange.getBegin()),
196 commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
197 ArgRange);
198 commit.insertWrap("[", ArgRange, "]");
199 maybePutParensOnReceiver(Rec, commit);
200 return true;
201}
202
204 const ObjCMessageExpr *Msg,
205 const NSAPI &NS,
206 Commit &commit) {
207 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
209 return false;
210 return rewriteToSubscriptGetCommon(Msg, commit);
211}
212
214 const ObjCMessageExpr *Msg,
215 const NSAPI &NS,
216 Commit &commit) {
217 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
219 return false;
220 return rewriteToSubscriptGetCommon(Msg, commit);
221}
222
224 const ObjCMessageExpr *Msg,
225 const NSAPI &NS,
226 Commit &commit) {
227 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
229 return false;
230
231 if (Msg->getNumArgs() != 2)
232 return false;
233 const Expr *Rec = Msg->getInstanceReceiver();
234 if (!Rec)
235 return false;
236
237 SourceRange MsgRange = Msg->getSourceRange();
238 SourceRange RecRange = Rec->getSourceRange();
239 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
240 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
241
243 Arg0Range.getBegin()),
246 Arg1Range.getBegin()),
248 commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
249 Arg1Range);
250 commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
251 Arg1Range.getBegin()),
252 "] = ");
253 maybePutParensOnReceiver(Rec, commit);
254 return true;
255}
256
258 const ObjCMessageExpr *Msg,
259 const NSAPI &NS,
260 Commit &commit) {
261 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
263 return false;
264
265 if (Msg->getNumArgs() != 2)
266 return false;
267 const Expr *Rec = Msg->getInstanceReceiver();
268 if (!Rec)
269 return false;
270
271 SourceRange MsgRange = Msg->getSourceRange();
272 SourceRange RecRange = Rec->getSourceRange();
273 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
274 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
275
276 SourceLocation LocBeforeVal = Arg0Range.getBegin();
277 commit.insertBefore(LocBeforeVal, "] = ");
278 commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
279 /*beforePreviousInsertions=*/true);
280 commit.insertBefore(LocBeforeVal, "[");
282 Arg0Range.getBegin()),
284 commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
285 Arg0Range);
286 maybePutParensOnReceiver(Rec, commit);
287 return true;
288}
289
291 const NSAPI &NS, Commit &commit) {
292 if (!Msg || Msg->isImplicit() ||
294 return false;
295 const ObjCMethodDecl *Method = Msg->getMethodDecl();
296 if (!Method)
297 return false;
298
299 const ObjCInterfaceDecl *IFace =
301 if (!IFace)
302 return false;
303 Selector Sel = Msg->getSelector();
304
306 return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
307
309 return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
310
311 if (Msg->getNumArgs() != 2)
312 return false;
313
315 return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
316
318 return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
319
320 return false;
321}
322
323//===----------------------------------------------------------------------===//
324// rewriteToObjCLiteralSyntax.
325//===----------------------------------------------------------------------===//
326
327static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
328 const NSAPI &NS, Commit &commit,
329 const ParentMap *PMap);
330static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
331 const NSAPI &NS, Commit &commit);
332static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
333 const NSAPI &NS, Commit &commit);
335 const NSAPI &NS, Commit &commit);
337 const NSAPI &NS, Commit &commit);
338
340 const NSAPI &NS, Commit &commit,
341 const ParentMap *PMap) {
342 IdentifierInfo *II = nullptr;
344 return false;
345
347 return rewriteToArrayLiteral(Msg, NS, commit, PMap);
349 return rewriteToDictionaryLiteral(Msg, NS, commit);
351 return rewriteToNumberLiteral(Msg, NS, commit);
353 return rewriteToStringBoxedExpression(Msg, NS, commit);
354
355 return false;
356}
357
358/// Returns true if the immediate message arguments of \c Msg should not
359/// be rewritten because it will interfere with the rewrite of the parent
360/// message expression. e.g.
361/// \code
362/// [NSDictionary dictionaryWithObjects:
363/// [NSArray arrayWithObjects:@"1", @"2", nil]
364/// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
365/// \endcode
366/// It will return true for this because we are going to rewrite this directly
367/// to a dictionary literal without any array literals.
369 const NSAPI &NS);
370
371//===----------------------------------------------------------------------===//
372// rewriteToArrayLiteral.
373//===----------------------------------------------------------------------===//
374
375/// Adds an explicit cast to 'id' if the type is not objc object.
376static void objectifyExpr(const Expr *E, Commit &commit);
377
379 const NSAPI &NS, Commit &commit,
380 const ParentMap *PMap) {
381 if (PMap) {
382 const ObjCMessageExpr *ParentMsg =
383 dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
384 if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
385 return false;
386 }
387
388 Selector Sel = Msg->getSelector();
389 SourceRange MsgRange = Msg->getSourceRange();
390
391 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
392 if (Msg->getNumArgs() != 0)
393 return false;
394 commit.replace(MsgRange, "@[]");
395 return true;
396 }
397
399 if (Msg->getNumArgs() != 1)
400 return false;
401 objectifyExpr(Msg->getArg(0), commit);
402 SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
403 commit.replaceWithInner(MsgRange, ArgRange);
404 commit.insertWrap("@[", ArgRange, "]");
405 return true;
406 }
407
410 if (Msg->getNumArgs() == 0)
411 return false;
412 const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
413 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
414 return false;
415
416 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
417 objectifyExpr(Msg->getArg(i), commit);
418
419 if (Msg->getNumArgs() == 1) {
420 commit.replace(MsgRange, "@[]");
421 return true;
422 }
423 SourceRange ArgRange(Msg->getArg(0)->getBeginLoc(),
424 Msg->getArg(Msg->getNumArgs() - 2)->getEndLoc());
425 commit.replaceWithInner(MsgRange, ArgRange);
426 commit.insertWrap("@[", ArgRange, "]");
427 return true;
428 }
429
430 return false;
431}
432
433//===----------------------------------------------------------------------===//
434// rewriteToDictionaryLiteral.
435//===----------------------------------------------------------------------===//
436
437/// If \c Msg is an NSArray creation message or literal, this gets the
438/// objects that were used to create it.
439/// \returns true if it is an NSArray and we got objects, or false otherwise.
440static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
442 if (!E)
443 return false;
444
445 E = E->IgnoreParenCasts();
446 if (!E)
447 return false;
448
449 if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
450 IdentifierInfo *Cls = nullptr;
452 return false;
453
455 return false;
456
457 Selector Sel = Msg->getSelector();
459 return true; // empty array.
460
462 if (Msg->getNumArgs() != 1)
463 return false;
464 Objs.push_back(Msg->getArg(0));
465 return true;
466 }
467
470 if (Msg->getNumArgs() == 0)
471 return false;
472 const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
473 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
474 return false;
475
476 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
477 Objs.push_back(Msg->getArg(i));
478 return true;
479 }
480
481 } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
482 for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
483 Objs.push_back(ArrLit->getElement(i));
484 return true;
485 }
486
487 return false;
488}
489
491 const NSAPI &NS, Commit &commit) {
492 Selector Sel = Msg->getSelector();
493 SourceRange MsgRange = Msg->getSourceRange();
494
496 if (Msg->getNumArgs() != 0)
497 return false;
498 commit.replace(MsgRange, "@{}");
499 return true;
500 }
501
502 if (Sel == NS.getNSDictionarySelector(
504 if (Msg->getNumArgs() != 2)
505 return false;
506
507 objectifyExpr(Msg->getArg(0), commit);
508 objectifyExpr(Msg->getArg(1), commit);
509
510 SourceRange ValRange = Msg->getArg(0)->getSourceRange();
511 SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
512 // Insert key before the value.
513 commit.insertBefore(ValRange.getBegin(), ": ");
514 commit.insertFromRange(ValRange.getBegin(),
516 /*afterToken=*/false, /*beforePreviousInsertions=*/true);
517 commit.insertBefore(ValRange.getBegin(), "@{");
518 commit.insertAfterToken(ValRange.getEnd(), "}");
519 commit.replaceWithInner(MsgRange, ValRange);
520 return true;
521 }
522
523 if (Sel == NS.getNSDictionarySelector(
526 if (Msg->getNumArgs() % 2 != 1)
527 return false;
528 unsigned SentinelIdx = Msg->getNumArgs() - 1;
529 const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
530 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
531 return false;
532
533 if (Msg->getNumArgs() == 1) {
534 commit.replace(MsgRange, "@{}");
535 return true;
536 }
537
538 for (unsigned i = 0; i < SentinelIdx; i += 2) {
539 objectifyExpr(Msg->getArg(i), commit);
540 objectifyExpr(Msg->getArg(i+1), commit);
541
542 SourceRange ValRange = Msg->getArg(i)->getSourceRange();
543 SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
544 // Insert value after key.
545 commit.insertAfterToken(KeyRange.getEnd(), ": ");
546 commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
548 KeyRange.getBegin()));
549 }
550 // Range of arguments up until and including the last key.
551 // The sentinel and first value are cut off, the value will move after the
552 // key.
553 SourceRange ArgRange(Msg->getArg(1)->getBeginLoc(),
554 Msg->getArg(SentinelIdx - 1)->getEndLoc());
555 commit.insertWrap("@{", ArgRange, "}");
556 commit.replaceWithInner(MsgRange, ArgRange);
557 return true;
558 }
559
560 if (Sel == NS.getNSDictionarySelector(
563 if (Msg->getNumArgs() != 2)
564 return false;
565
567 if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
568 return false;
569
571 if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
572 return false;
573
574 if (Vals.size() != Keys.size())
575 return false;
576
577 if (Vals.empty()) {
578 commit.replace(MsgRange, "@{}");
579 return true;
580 }
581
582 for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
583 objectifyExpr(Vals[i], commit);
584 objectifyExpr(Keys[i], commit);
585
586 SourceRange ValRange = Vals[i]->getSourceRange();
587 SourceRange KeyRange = Keys[i]->getSourceRange();
588 // Insert value after key.
589 commit.insertAfterToken(KeyRange.getEnd(), ": ");
590 commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
591 }
592 // Range of arguments up until and including the last key.
593 // The first value is cut off, the value will move after the key.
594 SourceRange ArgRange(Keys.front()->getBeginLoc(), Keys.back()->getEndLoc());
595 commit.insertWrap("@{", ArgRange, "}");
596 commit.replaceWithInner(MsgRange, ArgRange);
597 return true;
598 }
599
600 return false;
601}
602
604 const NSAPI &NS) {
605 if (!Msg)
606 return false;
607
608 IdentifierInfo *II = nullptr;
610 return false;
611
613 return false;
614
615 Selector Sel = Msg->getSelector();
616 if (Sel == NS.getNSDictionarySelector(
619 if (Msg->getNumArgs() != 2)
620 return false;
621
623 if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
624 return false;
625
627 if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
628 return false;
629
630 if (Vals.size() != Keys.size())
631 return false;
632
633 return true;
634 }
635
636 return false;
637}
638
639//===----------------------------------------------------------------------===//
640// rewriteToNumberLiteral.
641//===----------------------------------------------------------------------===//
642
644 const CharacterLiteral *Arg,
645 const NSAPI &NS, Commit &commit) {
646 if (Arg->getKind() != CharacterLiteralKind::Ascii)
647 return false;
649 Msg->getSelector())) {
650 SourceRange ArgRange = Arg->getSourceRange();
651 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
652 commit.insert(ArgRange.getBegin(), "@");
653 return true;
654 }
655
656 return rewriteToNumericBoxedExpression(Msg, NS, commit);
657}
658
660 const Expr *Arg,
661 const NSAPI &NS, Commit &commit) {
663 Msg->getSelector())) {
664 SourceRange ArgRange = Arg->getSourceRange();
665 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
666 commit.insert(ArgRange.getBegin(), "@");
667 return true;
668 }
669
670 return rewriteToNumericBoxedExpression(Msg, NS, commit);
671}
672
673namespace {
674
675struct LiteralInfo {
676 bool Hex, Octal;
677 StringRef U, F, L, LL;
678 CharSourceRange WithoutSuffRange;
679};
680
681}
682
683static bool getLiteralInfo(SourceRange literalRange,
684 bool isFloat, bool isIntZero,
685 ASTContext &Ctx, LiteralInfo &Info) {
686 if (literalRange.getBegin().isMacroID() ||
687 literalRange.getEnd().isMacroID())
688 return false;
689 StringRef text = Lexer::getSourceText(
690 CharSourceRange::getTokenRange(literalRange),
691 Ctx.getSourceManager(), Ctx.getLangOpts());
692 if (text.empty())
693 return false;
694
695 std::optional<bool> UpperU, UpperL;
696 bool UpperF = false;
697
698 struct Suff {
699 static bool has(StringRef suff, StringRef &text) {
700 return text.consume_back(suff);
701 }
702 };
703
704 while (true) {
705 if (Suff::has("u", text)) {
706 UpperU = false;
707 } else if (Suff::has("U", text)) {
708 UpperU = true;
709 } else if (Suff::has("ll", text)) {
710 UpperL = false;
711 } else if (Suff::has("LL", text)) {
712 UpperL = true;
713 } else if (Suff::has("l", text)) {
714 UpperL = false;
715 } else if (Suff::has("L", text)) {
716 UpperL = true;
717 } else if (isFloat && Suff::has("f", text)) {
718 UpperF = false;
719 } else if (isFloat && Suff::has("F", text)) {
720 UpperF = true;
721 } else
722 break;
723 }
724
725 if (!UpperU && !UpperL)
726 UpperU = UpperL = true;
727 else if (UpperU && !UpperL)
728 UpperL = UpperU;
729 else if (UpperL && !UpperU)
730 UpperU = UpperL;
731
732 Info.U = *UpperU ? "U" : "u";
733 Info.L = *UpperL ? "L" : "l";
734 Info.LL = *UpperL ? "LL" : "ll";
735 Info.F = UpperF ? "F" : "f";
736
737 Info.Hex = Info.Octal = false;
738 if (text.starts_with("0x"))
739 Info.Hex = true;
740 else if (!isFloat && !isIntZero && text.starts_with("0"))
741 Info.Octal = true;
742
743 SourceLocation B = literalRange.getBegin();
744 Info.WithoutSuffRange =
746 return true;
747}
748
750 const NSAPI &NS, Commit &commit) {
751 if (Msg->getNumArgs() != 1)
752 return false;
753
754 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
755 if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
756 return rewriteToCharLiteral(Msg, CharE, NS, commit);
757 if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
758 return rewriteToBoolLiteral(Msg, BE, NS, commit);
759 if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
760 return rewriteToBoolLiteral(Msg, BE, NS, commit);
761
762 const Expr *literalE = Arg;
763 if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
764 if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
765 literalE = UOE->getSubExpr();
766 }
767
768 // Only integer and floating literals, otherwise try to rewrite to boxed
769 // expression.
770 if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
771 return rewriteToNumericBoxedExpression(Msg, NS, commit);
772
773 ASTContext &Ctx = NS.getASTContext();
774 Selector Sel = Msg->getSelector();
775 std::optional<NSAPI::NSNumberLiteralMethodKind> MKOpt =
777 if (!MKOpt)
778 return false;
780
781 bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
782 bool CallIsFloating = false, CallIsDouble = false;
783
784 switch (MK) {
785 // We cannot have these calls with int/float literals.
791 return rewriteToNumericBoxedExpression(Msg, NS, commit);
792
795 CallIsUnsigned = true;
796 [[fallthrough]];
799 break;
800
802 CallIsUnsigned = true;
803 [[fallthrough]];
805 CallIsLong = true;
806 break;
807
809 CallIsUnsigned = true;
810 [[fallthrough]];
812 CallIsLongLong = true;
813 break;
814
816 CallIsDouble = true;
817 [[fallthrough]];
819 CallIsFloating = true;
820 break;
821 }
822
823 SourceRange ArgRange = Arg->getSourceRange();
824 QualType ArgTy = Arg->getType();
825 QualType CallTy = Msg->getArg(0)->getType();
826
827 // Check for the easy case, the literal maps directly to the call.
828 if (Ctx.hasSameType(ArgTy, CallTy)) {
829 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
830 commit.insert(ArgRange.getBegin(), "@");
831 return true;
832 }
833
834 // We will need to modify the literal suffix to get the same type as the call.
835 // Try with boxed expression if it came from a macro.
836 if (ArgRange.getBegin().isMacroID())
837 return rewriteToNumericBoxedExpression(Msg, NS, commit);
838
839 bool LitIsFloat = ArgTy->isFloatingType();
840 // For a float passed to integer call, don't try rewriting to objc literal.
841 // It is difficult and a very uncommon case anyway.
842 // But try with boxed expression.
843 if (LitIsFloat && !CallIsFloating)
844 return rewriteToNumericBoxedExpression(Msg, NS, commit);
845
846 // Try to modify the literal make it the same type as the method call.
847 // -Modify the suffix, and/or
848 // -Change integer to float
849
850 LiteralInfo LitInfo;
851 bool isIntZero = false;
852 if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
853 isIntZero = !IntE->getValue().getBoolValue();
854 if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
855 return rewriteToNumericBoxedExpression(Msg, NS, commit);
856
857 // Not easy to do int -> float with hex/octal and uncommon anyway.
858 if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
859 return rewriteToNumericBoxedExpression(Msg, NS, commit);
860
861 SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
862 SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
863
865 LitInfo.WithoutSuffRange);
866 commit.insert(LitB, "@");
867
868 if (!LitIsFloat && CallIsFloating)
869 commit.insert(LitE, ".0");
870
871 if (CallIsFloating) {
872 if (!CallIsDouble)
873 commit.insert(LitE, LitInfo.F);
874 } else {
875 if (CallIsUnsigned)
876 commit.insert(LitE, LitInfo.U);
877
878 if (CallIsLong)
879 commit.insert(LitE, LitInfo.L);
880 else if (CallIsLongLong)
881 commit.insert(LitE, LitInfo.LL);
882 }
883 return true;
884}
885
886// FIXME: Make determination of operator precedence more general and
887// make it broadly available.
889 const Expr* Expr = FullExpr->IgnoreImpCasts();
890 if (isa<ArraySubscriptExpr>(Expr) ||
891 isa<CallExpr>(Expr) ||
892 isa<DeclRefExpr>(Expr) ||
893 isa<CXXNamedCastExpr>(Expr) ||
894 isa<CXXConstructExpr>(Expr) ||
895 isa<CXXThisExpr>(Expr) ||
896 isa<CXXTypeidExpr>(Expr) ||
897 isa<CXXUnresolvedConstructExpr>(Expr) ||
898 isa<ObjCMessageExpr>(Expr) ||
899 isa<ObjCPropertyRefExpr>(Expr) ||
900 isa<ObjCProtocolExpr>(Expr) ||
901 isa<MemberExpr>(Expr) ||
902 isa<ObjCIvarRefExpr>(Expr) ||
903 isa<ParenExpr>(FullExpr) ||
904 isa<ParenListExpr>(Expr) ||
905 isa<SizeOfPackExpr>(Expr))
906 return false;
907
908 return true;
909}
911 const Expr* Expr = FullExpr->IgnoreImpCasts();
912 if (isa<ArraySubscriptExpr>(Expr) ||
913 isa<CallExpr>(Expr) ||
914 isa<DeclRefExpr>(Expr) ||
915 isa<CastExpr>(Expr) ||
916 isa<CXXNewExpr>(Expr) ||
917 isa<CXXConstructExpr>(Expr) ||
918 isa<CXXDeleteExpr>(Expr) ||
919 isa<CXXNoexceptExpr>(Expr) ||
920 isa<CXXPseudoDestructorExpr>(Expr) ||
921 isa<CXXScalarValueInitExpr>(Expr) ||
922 isa<CXXThisExpr>(Expr) ||
923 isa<CXXTypeidExpr>(Expr) ||
924 isa<CXXUnresolvedConstructExpr>(Expr) ||
925 isa<ObjCMessageExpr>(Expr) ||
926 isa<ObjCPropertyRefExpr>(Expr) ||
927 isa<ObjCProtocolExpr>(Expr) ||
928 isa<MemberExpr>(Expr) ||
929 isa<ObjCIvarRefExpr>(Expr) ||
930 isa<ParenExpr>(FullExpr) ||
931 isa<ParenListExpr>(Expr) ||
932 isa<SizeOfPackExpr>(Expr) ||
933 isa<UnaryOperator>(Expr))
934 return false;
935
936 return true;
937}
938
939static void objectifyExpr(const Expr *E, Commit &commit) {
940 if (!E) return;
941
942 QualType T = E->getType();
943 if (T->isObjCObjectPointerType()) {
944 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
945 if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
946 return;
947 } else {
948 return;
949 }
950 } else if (!T->isPointerType()) {
951 return;
952 }
953
954 SourceRange Range = E->getSourceRange();
956 commit.insertWrap("(", Range, ")");
957 commit.insertBefore(Range.getBegin(), "(id)");
958}
959
960//===----------------------------------------------------------------------===//
961// rewriteToNumericBoxedExpression.
962//===----------------------------------------------------------------------===//
963
964static bool isEnumConstant(const Expr *E) {
965 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
966 if (const ValueDecl *VD = DRE->getDecl())
967 return isa<EnumConstantDecl>(VD);
968
969 return false;
970}
971
973 const NSAPI &NS, Commit &commit) {
974 if (Msg->getNumArgs() != 1)
975 return false;
976
977 const Expr *Arg = Msg->getArg(0);
978 if (Arg->isTypeDependent())
979 return false;
980
981 ASTContext &Ctx = NS.getASTContext();
982 Selector Sel = Msg->getSelector();
983 std::optional<NSAPI::NSNumberLiteralMethodKind> MKOpt =
985 if (!MKOpt)
986 return false;
988
989 const Expr *OrigArg = Arg->IgnoreImpCasts();
990 QualType FinalTy = Arg->getType();
991 QualType OrigTy = OrigArg->getType();
992 uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
993 uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
994
995 bool isTruncated = FinalTySize < OrigTySize;
996 bool needsCast = false;
997
998 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
999 switch (ICE->getCastKind()) {
1000 case CK_LValueToRValue:
1001 case CK_NoOp:
1002 case CK_UserDefinedConversion:
1003 case CK_HLSLArrayRValue:
1004 break;
1005
1006 case CK_IntegralCast: {
1007 if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
1008 break;
1009 // Be more liberal with Integer/UnsignedInteger which are very commonly
1010 // used.
1011 if ((MK == NSAPI::NSNumberWithInteger ||
1013 !isTruncated) {
1014 if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
1015 break;
1016 if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
1017 OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
1018 break;
1019 }
1020
1021 needsCast = true;
1022 break;
1023 }
1024
1025 case CK_PointerToBoolean:
1026 case CK_IntegralToBoolean:
1027 case CK_IntegralToFloating:
1028 case CK_FloatingToIntegral:
1029 case CK_FloatingToBoolean:
1030 case CK_FloatingCast:
1031 case CK_FloatingComplexToReal:
1032 case CK_FloatingComplexToBoolean:
1033 case CK_IntegralComplexToReal:
1034 case CK_IntegralComplexToBoolean:
1035 case CK_AtomicToNonAtomic:
1036 case CK_AddressSpaceConversion:
1037 needsCast = true;
1038 break;
1039
1040 case CK_Dependent:
1041 case CK_BitCast:
1042 case CK_LValueBitCast:
1043 case CK_LValueToRValueBitCast:
1044 case CK_BaseToDerived:
1045 case CK_DerivedToBase:
1046 case CK_UncheckedDerivedToBase:
1047 case CK_Dynamic:
1048 case CK_ToUnion:
1049 case CK_ArrayToPointerDecay:
1050 case CK_FunctionToPointerDecay:
1051 case CK_NullToPointer:
1052 case CK_NullToMemberPointer:
1053 case CK_BaseToDerivedMemberPointer:
1054 case CK_DerivedToBaseMemberPointer:
1055 case CK_MemberPointerToBoolean:
1056 case CK_ReinterpretMemberPointer:
1057 case CK_ConstructorConversion:
1058 case CK_IntegralToPointer:
1059 case CK_PointerToIntegral:
1060 case CK_ToVoid:
1061 case CK_VectorSplat:
1062 case CK_CPointerToObjCPointerCast:
1063 case CK_BlockPointerToObjCPointerCast:
1064 case CK_AnyPointerToBlockPointerCast:
1065 case CK_ObjCObjectLValueCast:
1066 case CK_FloatingRealToComplex:
1067 case CK_FloatingComplexCast:
1068 case CK_FloatingComplexToIntegralComplex:
1069 case CK_IntegralRealToComplex:
1070 case CK_IntegralComplexCast:
1071 case CK_IntegralComplexToFloatingComplex:
1072 case CK_ARCProduceObject:
1073 case CK_ARCConsumeObject:
1074 case CK_ARCReclaimReturnedObject:
1075 case CK_ARCExtendBlockObject:
1076 case CK_NonAtomicToAtomic:
1077 case CK_CopyAndAutoreleaseBlockObject:
1078 case CK_BuiltinFnToFnPtr:
1079 case CK_ZeroToOCLOpaqueType:
1080 case CK_IntToOCLSampler:
1081 case CK_MatrixCast:
1082 return false;
1083
1084 case CK_BooleanToSignedIntegral:
1085 llvm_unreachable("OpenCL-specific cast in Objective-C?");
1086
1087 case CK_HLSLVectorTruncation:
1088 llvm_unreachable("HLSL-specific cast in Objective-C?");
1089 break;
1090
1091 case CK_FloatingToFixedPoint:
1092 case CK_FixedPointToFloating:
1093 case CK_FixedPointCast:
1094 case CK_FixedPointToBoolean:
1095 case CK_FixedPointToIntegral:
1096 case CK_IntegralToFixedPoint:
1097 llvm_unreachable("Fixed point types are disabled for Objective-C");
1098 }
1099 }
1100
1101 if (needsCast) {
1102 DiagnosticsEngine &Diags = Ctx.getDiagnostics();
1103 // FIXME: Use a custom category name to distinguish migration diagnostics.
1104 unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
1105 "converting to boxing syntax requires casting %0 to %1");
1106 Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
1107 << Msg->getSourceRange();
1108 return false;
1109 }
1110
1111 SourceRange ArgRange = OrigArg->getSourceRange();
1112 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1113
1114 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1115 commit.insertBefore(ArgRange.getBegin(), "@");
1116 else
1117 commit.insertWrap("@(", ArgRange, ")");
1118
1119 return true;
1120}
1121
1122//===----------------------------------------------------------------------===//
1123// rewriteToStringBoxedExpression.
1124//===----------------------------------------------------------------------===//
1125
1127 const ObjCMessageExpr *Msg,
1128 const NSAPI &NS, Commit &commit) {
1129 const Expr *Arg = Msg->getArg(0);
1130 if (Arg->isTypeDependent())
1131 return false;
1132
1133 ASTContext &Ctx = NS.getASTContext();
1134
1135 const Expr *OrigArg = Arg->IgnoreImpCasts();
1136 QualType OrigTy = OrigArg->getType();
1137 if (OrigTy->isArrayType())
1138 OrigTy = Ctx.getArrayDecayedType(OrigTy);
1139
1140 if (const StringLiteral *
1141 StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
1142 commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
1143 commit.insert(StrE->getBeginLoc(), "@");
1144 return true;
1145 }
1146
1147 if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
1148 QualType PointeeType = PT->getPointeeType();
1149 if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
1150 SourceRange ArgRange = OrigArg->getSourceRange();
1151 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1152
1153 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1154 commit.insertBefore(ArgRange.getBegin(), "@");
1155 else
1156 commit.insertWrap("@(", ArgRange, ")");
1157
1158 return true;
1159 }
1160 }
1161
1162 return false;
1163}
1164
1166 const NSAPI &NS, Commit &commit) {
1167 Selector Sel = Msg->getSelector();
1168
1172 if (Msg->getNumArgs() != 1)
1173 return false;
1174 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1175 }
1176
1178 if (Msg->getNumArgs() != 2)
1179 return false;
1180
1181 const Expr *encodingArg = Msg->getArg(1);
1182 if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
1183 NS.isNSASCIIStringEncodingConstant(encodingArg))
1184 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1185 }
1186
1187 return false;
1188}
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool isEnumConstant(const Expr *E)
static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg, const NSAPI &NS)
Returns true if the immediate message arguments of Msg should not be rewritten because it will interf...
static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg, const CharacterLiteral *Arg, const NSAPI &NS, Commit &commit)
static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace, const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit)
static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg, const Expr *Arg, const NSAPI &NS, Commit &commit)
static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit, const ParentMap *PMap)
static bool subscriptOperatorNeedsParens(const Expr *FullExpr)
static const ObjCInterfaceDecl * maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace, const Expr *Receiver, ASTContext &Ctx)
Check for classes that accept 'objectForKey:' (or the other selectors that the migrator handles) but ...
static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static bool castOperatorNeedsParens(const Expr *FullExpr)
static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg, Commit &commit)
static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace, const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static bool doRewriteToUTF8StringBoxedExpressionHelper(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static bool getNSArrayObjects(const Expr *E, const NSAPI &NS, SmallVectorImpl< const Expr * > &Objs)
If Msg is an NSArray creation message or literal, this gets the objects that were used to create it.
static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace, const ObjCMessageExpr *Msg, ASTContext &Ctx, Selector subscriptSel)
static bool getLiteralInfo(SourceRange literalRange, bool isFloat, bool isIntZero, ASTContext &Ctx, LiteralInfo &Info)
static void objectifyExpr(const Expr *E, Commit &commit)
Adds an explicit cast to 'id' if the type is not objc object.
static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace, const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
static bool checkForLiteralCreation(const ObjCMessageExpr *Msg, IdentifierInfo *&ClassId, const LangOptions &LangOpts)
static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace, const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
SourceManager & getSourceManager()
Definition: ASTContext.h:705
bool isObjCIdType(QualType T) const
Definition: ASTContext.h:2899
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
Definition: ASTContext.h:2590
const LangOptions & getLangOpts() const
Definition: ASTContext.h:775
CanQualType CharTy
Definition: ASTContext.h:1093
CanQualType IntTy
Definition: ASTContext.h:1100
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2617
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2340
QualType getArrayDecayedType(QualType T) const
Return the properly qualified result of decaying the specified array type to a pointer.
const ObjCInterfaceDecl * getObjContainingInterface(const NamedDecl *ND) const
Returns the Objective-C interface that ND belongs to if it is an Objective-C method/property/ivar etc...
DiagnosticsEngine & getDiagnostics() const
bool isSentinelNullExpr(const Expr *E)
A boolean literal, per ([C++ lex.bool] Boolean literals).
Definition: ExprCXX.h:720
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
static CharSourceRange getTokenRange(SourceRange R)
CharacterLiteralKind getKind() const
Definition: Expr.h:1603
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1260
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
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of enums.
Definition: Type.h:5571
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
bool isTypeDependent() const
Determines whether the type of this expression depends on.
Definition: Expr.h:192
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:3059
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3055
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3039
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:277
QualType getType() const
Definition: Expr.h:142
FullExpr - Represents a "full-expression" node.
Definition: Expr.h:1039
One of these records is kept for each identifier that is lexed.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:3655
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:461
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Definition: Lexer.cpp:1024
std::optional< NSNumberLiteralMethodKind > getNSNumberLiteralMethodKind(Selector Sel) const
Return NSNumberLiteralMethodKind if Sel is such a selector.
Definition: NSAPI.cpp:338
Selector getObjectAtIndexedSubscriptSelector() const
Returns selector for "objectAtIndexedSubscript:".
Definition: NSAPI.h:143
@ NSStr_initWithUTF8String
Definition: NSAPI.h:49
@ NSStr_initWithString
Definition: NSAPI.h:48
@ NSStr_stringWithCString
Definition: NSAPI.h:47
@ NSStr_stringWithString
Definition: NSAPI.h:44
@ NSStr_stringWithCStringEncoding
Definition: NSAPI.h:46
@ NSStr_stringWithUTF8String
Definition: NSAPI.h:45
Selector getSetObjectAtIndexedSubscriptSelector() const
Returns selector for "setObject:atIndexedSubscript".
Definition: NSAPI.h:155
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const
The Objective-C NSDictionary selectors.
Definition: NSAPI.cpp:148
@ ClassId_NSDictionary
Definition: NSAPI.h:34
@ ClassId_NSNumber
Definition: NSAPI.h:36
@ ClassId_NSArray
Definition: NSAPI.h:32
@ ClassId_NSString
Definition: NSAPI.h:31
Selector getObjectForKeyedSubscriptSelector() const
Returns selector for "objectForKeyedSubscript:".
Definition: NSAPI.h:137
@ NSDict_objectForKey
Definition: NSAPI.h:106
@ NSDict_dictionaryWithObjectsForKeys
Definition: NSAPI.h:100
@ NSDict_dictionaryWithDictionary
Definition: NSAPI.h:98
@ NSMutableDict_setObjectForKey
Definition: NSAPI.h:107
@ NSDict_initWithObjectsForKeys
Definition: NSAPI.h:105
@ NSDict_dictionaryWithObjectForKey
Definition: NSAPI.h:99
@ NSDict_dictionary
Definition: NSAPI.h:97
@ NSDict_initWithDictionary
Definition: NSAPI.h:103
@ NSDict_initWithObjectsAndKeys
Definition: NSAPI.h:104
@ NSDict_dictionaryWithObjectsAndKeys
Definition: NSAPI.h:102
Selector getNSArraySelector(NSArrayMethodKind MK) const
The Objective-C NSArray selectors.
Definition: NSAPI.cpp:77
@ NSArr_arrayWithObjects
Definition: NSAPI.h:76
@ NSArr_objectAtIndex
Definition: NSAPI.h:80
@ NSArr_arrayWithArray
Definition: NSAPI.h:74
@ NSArr_array
Definition: NSAPI.h:73
@ NSArr_initWithObjects
Definition: NSAPI.h:79
@ NSMutableArr_replaceObjectAtIndex
Definition: NSAPI.h:81
@ NSArr_initWithArray
Definition: NSAPI.h:78
@ NSArr_arrayWithObject
Definition: NSAPI.h:75
bool isNSUTF8StringEncodingConstant(const Expr *E) const
Returns true if the expression.
Definition: NSAPI.h:60
bool isNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, Selector Sel) const
Definition: NSAPI.h:199
Selector getSetObjectForKeyedSubscriptSelector() const
Returns selector for "setObject:forKeyedSubscript".
Definition: NSAPI.h:149
ASTContext & getASTContext() const
Definition: NSAPI.h:27
NSNumberLiteralMethodKind
Enumerates the NSNumber methods used to generate literals.
Definition: NSAPI.h:174
@ NSNumberWithChar
Definition: NSAPI.h:175
@ NSNumberWithInteger
Definition: NSAPI.h:188
@ NSNumberWithDouble
Definition: NSAPI.h:186
@ NSNumberWithUnsignedChar
Definition: NSAPI.h:176
@ NSNumberWithUnsignedLongLong
Definition: NSAPI.h:184
@ NSNumberWithBool
Definition: NSAPI.h:187
@ NSNumberWithUnsignedInt
Definition: NSAPI.h:180
@ NSNumberWithLongLong
Definition: NSAPI.h:183
@ NSNumberWithLong
Definition: NSAPI.h:181
@ NSNumberWithFloat
Definition: NSAPI.h:185
@ NSNumberWithUnsignedLong
Definition: NSAPI.h:182
@ NSNumberWithShort
Definition: NSAPI.h:177
@ NSNumberWithUnsignedInteger
Definition: NSAPI.h:189
@ NSNumberWithInt
Definition: NSAPI.h:179
@ NSNumberWithUnsignedShort
Definition: NSAPI.h:178
Selector getNSStringSelector(NSStringMethodKind MK) const
The Objective-C NSString selectors.
Definition: NSAPI.cpp:43
bool isNSASCIIStringEncodingConstant(const Expr *E) const
Returns true if the expression.
Definition: NSAPI.h:66
IdentifierInfo * getNSClassId(NSClassIdKindKind K) const
Definition: NSAPI.cpp:23
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
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Definition: ExprObjC.h:191
ObjCBoolLiteralExpr - Objective-C Boolean Literal.
Definition: ExprObjC.h:87
Represents an ObjC class declaration.
Definition: DeclObjC.h:1153
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
Definition: DeclObjC.h:1845
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:945
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: ExprObjC.h:1395
bool isImplicit() const
Indicates whether the message send was implicitly generated by the implementation.
Definition: ExprObjC.h:1230
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1260
Selector getSelector() const
Definition: ExprObjC.cpp:293
@ 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
@ SuperClass
The receiver is a superclass.
Definition: ExprObjC.h:956
@ Class
The receiver is a class.
Definition: ExprObjC.h:950
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
Definition: ExprObjC.h:1279
ObjCInterfaceDecl * getReceiverInterface() const
Retrieve the Objective-C interface to which this message is being directed, if known.
Definition: ExprObjC.cpp:314
QualType getSuperType() const
Retrieve the type referred to by 'super'.
Definition: ExprObjC.h:1336
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
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
Represents a class type in Objective C.
Definition: Type.h:6750
ObjCInterfaceDecl * getInterface() const
Gets the interface declaration for this object type, if the base type really is an interface.
Definition: Type.h:6983
Stmt * getParentIgnoreParenCasts(Stmt *) const
Definition: ParentMap.cpp:146
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:3135
A (possibly-)qualified type.
Definition: Type.h:940
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:1007
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:7449
Smart pointer class that efficiently represents Objective-C method names.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
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
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1773
bool isBooleanType() const
Definition: Type.h:8029
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition: Type.cpp:2134
bool isArrayType() const
Definition: Type.h:7674
bool isPointerType() const
Definition: Type.h:7608
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:694
bool isObjCObjectPointerType() const
Definition: Type.h:7740
bool isFloatingType() const
Definition: Type.cpp:2237
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8119
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2183
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:706
bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange)
Definition: Commit.cpp:132
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
const internal::ArgumentAdaptingMatcherFunc< internal::HasMatcher > has
Matches AST nodes that have child AST nodes that match the provided matcher.
bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit, const ParentMap *PMap)
bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
EditGenerator edit(ASTEdit E)
Generates a single (specified) edit.
Definition: RewriteRule.cpp:84
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T