clang 22.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
79
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) {
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.
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->isEnumeralType() || 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 case CK_HLSLElementwiseCast:
1089 case CK_HLSLAggregateSplatCast:
1090 llvm_unreachable("HLSL-specific cast in Objective-C?");
1091 break;
1092
1093 case CK_FloatingToFixedPoint:
1094 case CK_FixedPointToFloating:
1095 case CK_FixedPointCast:
1096 case CK_FixedPointToBoolean:
1097 case CK_FixedPointToIntegral:
1098 case CK_IntegralToFixedPoint:
1099 llvm_unreachable("Fixed point types are disabled for Objective-C");
1100 }
1101 }
1102
1103 if (needsCast) {
1104 DiagnosticsEngine &Diags = Ctx.getDiagnostics();
1105 // FIXME: Use a custom category name to distinguish migration diagnostics.
1106 unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
1107 "converting to boxing syntax requires casting %0 to %1");
1108 Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
1109 << Msg->getSourceRange();
1110 return false;
1111 }
1112
1113 SourceRange ArgRange = OrigArg->getSourceRange();
1114 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1115
1116 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1117 commit.insertBefore(ArgRange.getBegin(), "@");
1118 else
1119 commit.insertWrap("@(", ArgRange, ")");
1120
1121 return true;
1122}
1123
1124//===----------------------------------------------------------------------===//
1125// rewriteToStringBoxedExpression.
1126//===----------------------------------------------------------------------===//
1127
1129 const ObjCMessageExpr *Msg,
1130 const NSAPI &NS, Commit &commit) {
1131 const Expr *Arg = Msg->getArg(0);
1132 if (Arg->isTypeDependent())
1133 return false;
1134
1135 ASTContext &Ctx = NS.getASTContext();
1136
1137 const Expr *OrigArg = Arg->IgnoreImpCasts();
1138 QualType OrigTy = OrigArg->getType();
1139 if (OrigTy->isArrayType())
1140 OrigTy = Ctx.getArrayDecayedType(OrigTy);
1141
1142 if (const StringLiteral *
1143 StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
1144 commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
1145 commit.insert(StrE->getBeginLoc(), "@");
1146 return true;
1147 }
1148
1149 if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
1150 QualType PointeeType = PT->getPointeeType();
1151 if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
1152 SourceRange ArgRange = OrigArg->getSourceRange();
1153 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1154
1155 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1156 commit.insertBefore(ArgRange.getBegin(), "@");
1157 else
1158 commit.insertWrap("@(", ArgRange, ")");
1159
1160 return true;
1161 }
1162 }
1163
1164 return false;
1165}
1166
1168 const NSAPI &NS, Commit &commit) {
1169 Selector Sel = Msg->getSelector();
1170
1174 if (Msg->getNumArgs() != 1)
1175 return false;
1176 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1177 }
1178
1180 if (Msg->getNumArgs() != 2)
1181 return false;
1182
1183 const Expr *encodingArg = Msg->getArg(1);
1184 if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
1185 NS.isNSASCIIStringEncodingConstant(encodingArg))
1186 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1187 }
1188
1189 return false;
1190}
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool isEnumConstant(const Expr *Ex)
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:188
SourceManager & getSourceManager()
Definition ASTContext.h:798
bool isObjCIdType(QualType T) const
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
const LangOptions & getLangOpts() const
Definition ASTContext.h:891
CanQualType CharTy
CanQualType IntTy
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
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:723
static CharSourceRange getCharRange(SourceRange R)
static CharSourceRange getTokenRange(SourceRange R)
SourceLocation getEnd() const
SourceLocation getBegin() const
CharacterLiteralKind getKind() const
Definition Expr.h:1624
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1272
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:231
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
Definition Diagnostic.h:904
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3078
bool isTypeDependent() const
Determines whether the type of this expression depends on.
Definition Expr.h:194
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3073
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3069
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3053
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:273
QualType getType() const
Definition Expr.h:144
FullExpr - Represents a "full-expression" node.
Definition Expr.h:1051
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:3789
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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:1020
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:294
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:300
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Definition ExprObjC.h:192
ObjCBoolLiteralExpr - Objective-C Boolean Literal.
Definition ExprObjC.h:88
Represents an ObjC class declaration.
Definition DeclObjC.h:1154
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
Definition DeclObjC.h:1847
An expression that sends a message to the given Objective-C object or class.
Definition ExprObjC.h:940
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition ExprObjC.h:1403
bool isImplicit() const
Indicates whether the message send was implicitly generated by the implementation.
Definition ExprObjC.h:1225
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition ExprObjC.h:1268
Selector getSelector() const
Definition ExprObjC.cpp:289
@ SuperInstance
The receiver is the instance of the superclass object.
Definition ExprObjC.h:954
@ Instance
The receiver is an object instance.
Definition ExprObjC.h:948
@ SuperClass
The receiver is a superclass.
Definition ExprObjC.h:951
@ Class
The receiver is a class.
Definition ExprObjC.h:945
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
Definition ExprObjC.h:1287
ObjCInterfaceDecl * getReceiverInterface() const
Retrieve the Objective-C interface to which this message is being directed, if known.
Definition ExprObjC.cpp:310
QualType getSuperType() const
Retrieve the type referred to by 'super'.
Definition ExprObjC.h:1344
const ObjCMethodDecl * getMethodDecl() const
Definition ExprObjC.h:1364
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
Definition ExprObjC.h:1229
unsigned getNumArgs() const
Return the number of actual arguments in this message, not counting the receiver.
Definition ExprObjC.h:1390
ObjCMethodDecl - Represents an instance or class method declaration.
Definition DeclObjC.h:140
Stmt * getParentIgnoreParenCasts(Stmt *) const
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3328
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8379
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:358
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:334
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:346
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1801
bool isBooleanType() const
Definition TypeBase.h:9008
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2205
bool isArrayType() const
Definition TypeBase.h:8621
bool isEnumeralType() const
Definition TypeBase.h:8653
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
bool isFloatingType() const
Definition Type.cpp:2304
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9101
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2246
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:711
bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange)
Definition Commit.cpp:131
bool insertWrap(StringRef before, CharSourceRange range, StringRef after)
Definition Commit.cpp:102
bool insertFromRange(SourceLocation loc, CharSourceRange range, bool afterToken=false, bool beforePreviousInsertions=false)
Definition Commit.cpp:63
bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)
Definition Commit.cpp:47
bool insertAfterToken(SourceLocation loc, StringRef text, bool beforePreviousInsertions=false)
Definition Commit.h:73
bool remove(CharSourceRange range)
Definition Commit.cpp:90
bool insertBefore(SourceLocation loc, StringRef text)
Definition Commit.h:78
bool replace(CharSourceRange range, StringRef text)
Definition Commit.cpp:115
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)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
const FunctionProtoType * T