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 
13 #include "clang/Edit/Rewriters.h"
14 #include "clang/AST/ASTContext.h"
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 
23 using namespace clang;
24 using 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'.
108 static 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 
172 static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
173 
174 static 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()),
247  CharSourceRange::getTokenRange(Arg0Range));
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 
327 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
328  const NSAPI &NS, Commit &commit,
329  const ParentMap *PMap);
330 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
331  const NSAPI &NS, Commit &commit);
332 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
333  const NSAPI &NS, Commit &commit);
334 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
335  const NSAPI &NS, Commit &commit);
336 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
337  const NSAPI &NS, Commit &commit);
338 
340  const NSAPI &NS, Commit &commit,
341  const ParentMap *PMap) {
342  IdentifierInfo *II = nullptr;
343  if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
344  return false;
345 
346  if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
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.
376 static void objectifyExpr(const Expr *E, Commit &commit);
377 
378 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
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.
440 static 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;
451  if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
452  return false;
453 
454  if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
455  return false;
456 
457  Selector Sel = Msg->getSelector();
458  if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
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;
609  if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
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 
643 static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
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 
659 static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
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 
673 namespace {
674 
675 struct LiteralInfo {
676  bool Hex, Octal;
677  StringRef U, F, L, LL;
678  CharSourceRange WithoutSuffRange;
679 };
680 
681 }
682 
683 static 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 }
910 static bool castOperatorNeedsParens(const Expr *FullExpr) {
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 
939 static 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 
956  commit.insertWrap("(", Range, ")");
957  commit.insertBefore(Range.getBegin(), "(id)");
958 }
959 
960 //===----------------------------------------------------------------------===//
961 // rewriteToNumericBoxedExpression.
962 //===----------------------------------------------------------------------===//
963 
964 static 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 bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit)
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 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)
SourceRange Range
Definition: SemaObjC.cpp:754
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
SourceManager & getSourceManager()
Definition: ASTContext.h:708
bool isObjCIdType(QualType T) const
Definition: ASTContext.h:2914
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
Definition: ASTContext.h:2605
const LangOptions & getLangOpts() const
Definition: ASTContext.h:778
CanQualType CharTy
Definition: ASTContext.h:1096
CanQualType IntTy
Definition: ASTContext.h:1103
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2632
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2355
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:193
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1553
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
Definition: Diagnostic.h:879
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of enums.
Definition: Type.h:5587
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:3116
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:3111
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3107
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3091
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:3707
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:482
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
ASTContext & getASTContext() const
Definition: NSAPI.h:27
@ 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
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
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
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
bool isImplicit() const
Indicates whether the message send was implicitly generated by the implementation.
Definition: ExprObjC.h:1230
Selector getSelector() const
Definition: ExprObjC.cpp:293
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1260
@ 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
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: ExprObjC.h:1395
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:6766
ObjCInterfaceDecl * getInterface() const
Gets the interface declaration for this object type, if the base type really is an interface.
Definition: Type.h:6999
Stmt * getParentIgnoreParenCasts(Stmt *) const
Definition: ParentMap.cpp:162
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:3151
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:7465
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:8067
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition: Type.cpp:2145
bool isArrayType() const
Definition: Type.h:7690
bool isPointerType() const
Definition: Type.h:7624
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:705
bool isObjCObjectPointerType() const
Definition: Type.h:7760
bool isFloatingType() const
Definition: Type.cpp:2248
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8160
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2235
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:707
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
unsigned long uint64_t