RewriteObjCFoundationAPI.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  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. #include "clang/Edit/Rewriters.h"
  13. #include "clang/AST/ASTContext.h"
  14. #include "clang/AST/ExprCXX.h"
  15. #include "clang/AST/ExprObjC.h"
  16. #include "clang/AST/NSAPI.h"
  17. #include "clang/AST/ParentMap.h"
  18. #include "clang/Edit/Commit.h"
  19. #include "clang/Lex/Lexer.h"
  20. using namespace clang;
  21. using namespace edit;
  22. static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
  23. IdentifierInfo *&ClassId,
  24. const LangOptions &LangOpts) {
  25. if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
  26. return false;
  27. const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
  28. if (!Receiver)
  29. return false;
  30. ClassId = Receiver->getIdentifier();
  31. if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
  32. return true;
  33. // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
  34. // since the change from +1 to +0 will be handled fine by ARC.
  35. if (LangOpts.ObjCAutoRefCount) {
  36. if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
  37. if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
  38. Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
  39. if (Rec->getMethodFamily() == OMF_alloc)
  40. return true;
  41. }
  42. }
  43. }
  44. return false;
  45. }
  46. //===----------------------------------------------------------------------===//
  47. // rewriteObjCRedundantCallWithLiteral.
  48. //===----------------------------------------------------------------------===//
  49. bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
  50. const NSAPI &NS, Commit &commit) {
  51. IdentifierInfo *II = nullptr;
  52. if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
  53. return false;
  54. if (Msg->getNumArgs() != 1)
  55. return false;
  56. const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
  57. Selector Sel = Msg->getSelector();
  58. if ((isa<ObjCStringLiteral>(Arg) &&
  59. NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
  60. (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
  61. NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel)) ||
  62. (isa<ObjCArrayLiteral>(Arg) &&
  63. NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
  64. (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
  65. NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel)) ||
  66. (isa<ObjCDictionaryLiteral>(Arg) &&
  67. NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
  68. (NS.getNSDictionarySelector(
  69. NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
  70. NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
  71. commit.replaceWithInner(Msg->getSourceRange(),
  72. Msg->getArg(0)->getSourceRange());
  73. return true;
  74. }
  75. return false;
  76. }
  77. //===----------------------------------------------------------------------===//
  78. // rewriteToObjCSubscriptSyntax.
  79. //===----------------------------------------------------------------------===//
  80. /// Check for classes that accept 'objectForKey:' (or the other selectors
  81. /// that the migrator handles) but return their instances as 'id', resulting
  82. /// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
  83. ///
  84. /// When checking if we can convert to subscripting syntax, check whether
  85. /// the receiver is a result of a class method from a hardcoded list of
  86. /// such classes. In such a case return the specific class as the interface
  87. /// of the receiver.
  88. ///
  89. /// FIXME: Remove this when these classes start using 'instancetype'.
  90. static const ObjCInterfaceDecl *
  91. maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
  92. const Expr *Receiver,
  93. ASTContext &Ctx) {
  94. assert(IFace && Receiver);
  95. // If the receiver has type 'id'...
  96. if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
  97. return IFace;
  98. const ObjCMessageExpr *
  99. InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
  100. if (!InnerMsg)
  101. return IFace;
  102. QualType ClassRec;
  103. switch (InnerMsg->getReceiverKind()) {
  104. case ObjCMessageExpr::Instance:
  105. case ObjCMessageExpr::SuperInstance:
  106. return IFace;
  107. case ObjCMessageExpr::Class:
  108. ClassRec = InnerMsg->getClassReceiver();
  109. break;
  110. case ObjCMessageExpr::SuperClass:
  111. ClassRec = InnerMsg->getSuperType();
  112. break;
  113. }
  114. if (ClassRec.isNull())
  115. return IFace;
  116. // ...and it is the result of a class message...
  117. const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
  118. if (!ObjTy)
  119. return IFace;
  120. const ObjCInterfaceDecl *OID = ObjTy->getInterface();
  121. // ...and the receiving class is NSMapTable or NSLocale, return that
  122. // class as the receiving interface.
  123. if (OID->getName() == "NSMapTable" ||
  124. OID->getName() == "NSLocale")
  125. return OID;
  126. return IFace;
  127. }
  128. static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
  129. const ObjCMessageExpr *Msg,
  130. ASTContext &Ctx,
  131. Selector subscriptSel) {
  132. const Expr *Rec = Msg->getInstanceReceiver();
  133. if (!Rec)
  134. return false;
  135. IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
  136. if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
  137. if (!MD->isUnavailable())
  138. return true;
  139. }
  140. return false;
  141. }
  142. static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
  143. static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
  144. if (subscriptOperatorNeedsParens(Receiver)) {
  145. SourceRange RecRange = Receiver->getSourceRange();
  146. commit.insertWrap("(", RecRange, ")");
  147. }
  148. }
  149. static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
  150. Commit &commit) {
  151. if (Msg->getNumArgs() != 1)
  152. return false;
  153. const Expr *Rec = Msg->getInstanceReceiver();
  154. if (!Rec)
  155. return false;
  156. SourceRange MsgRange = Msg->getSourceRange();
  157. SourceRange RecRange = Rec->getSourceRange();
  158. SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
  159. commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
  160. ArgRange.getBegin()),
  161. CharSourceRange::getTokenRange(RecRange));
  162. commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
  163. ArgRange);
  164. commit.insertWrap("[", ArgRange, "]");
  165. maybePutParensOnReceiver(Rec, commit);
  166. return true;
  167. }
  168. static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
  169. const ObjCMessageExpr *Msg,
  170. const NSAPI &NS,
  171. Commit &commit) {
  172. if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
  173. NS.getObjectAtIndexedSubscriptSelector()))
  174. return false;
  175. return rewriteToSubscriptGetCommon(Msg, commit);
  176. }
  177. static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
  178. const ObjCMessageExpr *Msg,
  179. const NSAPI &NS,
  180. Commit &commit) {
  181. if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
  182. NS.getObjectForKeyedSubscriptSelector()))
  183. return false;
  184. return rewriteToSubscriptGetCommon(Msg, commit);
  185. }
  186. static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
  187. const ObjCMessageExpr *Msg,
  188. const NSAPI &NS,
  189. Commit &commit) {
  190. if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
  191. NS.getSetObjectAtIndexedSubscriptSelector()))
  192. return false;
  193. if (Msg->getNumArgs() != 2)
  194. return false;
  195. const Expr *Rec = Msg->getInstanceReceiver();
  196. if (!Rec)
  197. return false;
  198. SourceRange MsgRange = Msg->getSourceRange();
  199. SourceRange RecRange = Rec->getSourceRange();
  200. SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
  201. SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
  202. commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
  203. Arg0Range.getBegin()),
  204. CharSourceRange::getTokenRange(RecRange));
  205. commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
  206. Arg1Range.getBegin()),
  207. CharSourceRange::getTokenRange(Arg0Range));
  208. commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
  209. Arg1Range);
  210. commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
  211. Arg1Range.getBegin()),
  212. "] = ");
  213. maybePutParensOnReceiver(Rec, commit);
  214. return true;
  215. }
  216. static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
  217. const ObjCMessageExpr *Msg,
  218. const NSAPI &NS,
  219. Commit &commit) {
  220. if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
  221. NS.getSetObjectForKeyedSubscriptSelector()))
  222. return false;
  223. if (Msg->getNumArgs() != 2)
  224. return false;
  225. const Expr *Rec = Msg->getInstanceReceiver();
  226. if (!Rec)
  227. return false;
  228. SourceRange MsgRange = Msg->getSourceRange();
  229. SourceRange RecRange = Rec->getSourceRange();
  230. SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
  231. SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
  232. SourceLocation LocBeforeVal = Arg0Range.getBegin();
  233. commit.insertBefore(LocBeforeVal, "] = ");
  234. commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
  235. /*beforePreviousInsertions=*/true);
  236. commit.insertBefore(LocBeforeVal, "[");
  237. commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
  238. Arg0Range.getBegin()),
  239. CharSourceRange::getTokenRange(RecRange));
  240. commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
  241. Arg0Range);
  242. maybePutParensOnReceiver(Rec, commit);
  243. return true;
  244. }
  245. bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
  246. const NSAPI &NS, Commit &commit) {
  247. if (!Msg || Msg->isImplicit() ||
  248. Msg->getReceiverKind() != ObjCMessageExpr::Instance)
  249. return false;
  250. const ObjCMethodDecl *Method = Msg->getMethodDecl();
  251. if (!Method)
  252. return false;
  253. const ObjCInterfaceDecl *IFace =
  254. NS.getASTContext().getObjContainingInterface(Method);
  255. if (!IFace)
  256. return false;
  257. Selector Sel = Msg->getSelector();
  258. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
  259. return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
  260. if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
  261. return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
  262. if (Msg->getNumArgs() != 2)
  263. return false;
  264. if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
  265. return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
  266. if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
  267. return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
  268. return false;
  269. }
  270. //===----------------------------------------------------------------------===//
  271. // rewriteToObjCLiteralSyntax.
  272. //===----------------------------------------------------------------------===//
  273. static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
  274. const NSAPI &NS, Commit &commit,
  275. const ParentMap *PMap);
  276. static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
  277. const NSAPI &NS, Commit &commit);
  278. static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
  279. const NSAPI &NS, Commit &commit);
  280. static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
  281. const NSAPI &NS, Commit &commit);
  282. static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
  283. const NSAPI &NS, Commit &commit);
  284. bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
  285. const NSAPI &NS, Commit &commit,
  286. const ParentMap *PMap) {
  287. IdentifierInfo *II = nullptr;
  288. if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
  289. return false;
  290. if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
  291. return rewriteToArrayLiteral(Msg, NS, commit, PMap);
  292. if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
  293. return rewriteToDictionaryLiteral(Msg, NS, commit);
  294. if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
  295. return rewriteToNumberLiteral(Msg, NS, commit);
  296. if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
  297. return rewriteToStringBoxedExpression(Msg, NS, commit);
  298. return false;
  299. }
  300. /// Returns true if the immediate message arguments of \c Msg should not
  301. /// be rewritten because it will interfere with the rewrite of the parent
  302. /// message expression. e.g.
  303. /// \code
  304. /// [NSDictionary dictionaryWithObjects:
  305. /// [NSArray arrayWithObjects:@"1", @"2", nil]
  306. /// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
  307. /// \endcode
  308. /// It will return true for this because we are going to rewrite this directly
  309. /// to a dictionary literal without any array literals.
  310. static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
  311. const NSAPI &NS);
  312. //===----------------------------------------------------------------------===//
  313. // rewriteToArrayLiteral.
  314. //===----------------------------------------------------------------------===//
  315. /// Adds an explicit cast to 'id' if the type is not objc object.
  316. static void objectifyExpr(const Expr *E, Commit &commit);
  317. static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
  318. const NSAPI &NS, Commit &commit,
  319. const ParentMap *PMap) {
  320. if (PMap) {
  321. const ObjCMessageExpr *ParentMsg =
  322. dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
  323. if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
  324. return false;
  325. }
  326. Selector Sel = Msg->getSelector();
  327. SourceRange MsgRange = Msg->getSourceRange();
  328. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
  329. if (Msg->getNumArgs() != 0)
  330. return false;
  331. commit.replace(MsgRange, "@[]");
  332. return true;
  333. }
  334. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
  335. if (Msg->getNumArgs() != 1)
  336. return false;
  337. objectifyExpr(Msg->getArg(0), commit);
  338. SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
  339. commit.replaceWithInner(MsgRange, ArgRange);
  340. commit.insertWrap("@[", ArgRange, "]");
  341. return true;
  342. }
  343. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
  344. Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
  345. if (Msg->getNumArgs() == 0)
  346. return false;
  347. const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
  348. if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
  349. return false;
  350. for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
  351. objectifyExpr(Msg->getArg(i), commit);
  352. if (Msg->getNumArgs() == 1) {
  353. commit.replace(MsgRange, "@[]");
  354. return true;
  355. }
  356. SourceRange ArgRange(Msg->getArg(0)->getBeginLoc(),
  357. Msg->getArg(Msg->getNumArgs() - 2)->getEndLoc());
  358. commit.replaceWithInner(MsgRange, ArgRange);
  359. commit.insertWrap("@[", ArgRange, "]");
  360. return true;
  361. }
  362. return false;
  363. }
  364. //===----------------------------------------------------------------------===//
  365. // rewriteToDictionaryLiteral.
  366. //===----------------------------------------------------------------------===//
  367. /// If \c Msg is an NSArray creation message or literal, this gets the
  368. /// objects that were used to create it.
  369. /// \returns true if it is an NSArray and we got objects, or false otherwise.
  370. static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
  371. SmallVectorImpl<const Expr *> &Objs) {
  372. if (!E)
  373. return false;
  374. E = E->IgnoreParenCasts();
  375. if (!E)
  376. return false;
  377. if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
  378. IdentifierInfo *Cls = nullptr;
  379. if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
  380. return false;
  381. if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
  382. return false;
  383. Selector Sel = Msg->getSelector();
  384. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
  385. return true; // empty array.
  386. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
  387. if (Msg->getNumArgs() != 1)
  388. return false;
  389. Objs.push_back(Msg->getArg(0));
  390. return true;
  391. }
  392. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
  393. Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
  394. if (Msg->getNumArgs() == 0)
  395. return false;
  396. const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
  397. if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
  398. return false;
  399. for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
  400. Objs.push_back(Msg->getArg(i));
  401. return true;
  402. }
  403. } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
  404. for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
  405. Objs.push_back(ArrLit->getElement(i));
  406. return true;
  407. }
  408. return false;
  409. }
  410. static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
  411. const NSAPI &NS, Commit &commit) {
  412. Selector Sel = Msg->getSelector();
  413. SourceRange MsgRange = Msg->getSourceRange();
  414. if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
  415. if (Msg->getNumArgs() != 0)
  416. return false;
  417. commit.replace(MsgRange, "@{}");
  418. return true;
  419. }
  420. if (Sel == NS.getNSDictionarySelector(
  421. NSAPI::NSDict_dictionaryWithObjectForKey)) {
  422. if (Msg->getNumArgs() != 2)
  423. return false;
  424. objectifyExpr(Msg->getArg(0), commit);
  425. objectifyExpr(Msg->getArg(1), commit);
  426. SourceRange ValRange = Msg->getArg(0)->getSourceRange();
  427. SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
  428. // Insert key before the value.
  429. commit.insertBefore(ValRange.getBegin(), ": ");
  430. commit.insertFromRange(ValRange.getBegin(),
  431. CharSourceRange::getTokenRange(KeyRange),
  432. /*afterToken=*/false, /*beforePreviousInsertions=*/true);
  433. commit.insertBefore(ValRange.getBegin(), "@{");
  434. commit.insertAfterToken(ValRange.getEnd(), "}");
  435. commit.replaceWithInner(MsgRange, ValRange);
  436. return true;
  437. }
  438. if (Sel == NS.getNSDictionarySelector(
  439. NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
  440. Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
  441. if (Msg->getNumArgs() % 2 != 1)
  442. return false;
  443. unsigned SentinelIdx = Msg->getNumArgs() - 1;
  444. const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
  445. if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
  446. return false;
  447. if (Msg->getNumArgs() == 1) {
  448. commit.replace(MsgRange, "@{}");
  449. return true;
  450. }
  451. for (unsigned i = 0; i < SentinelIdx; i += 2) {
  452. objectifyExpr(Msg->getArg(i), commit);
  453. objectifyExpr(Msg->getArg(i+1), commit);
  454. SourceRange ValRange = Msg->getArg(i)->getSourceRange();
  455. SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
  456. // Insert value after key.
  457. commit.insertAfterToken(KeyRange.getEnd(), ": ");
  458. commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
  459. commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
  460. KeyRange.getBegin()));
  461. }
  462. // Range of arguments up until and including the last key.
  463. // The sentinel and first value are cut off, the value will move after the
  464. // key.
  465. SourceRange ArgRange(Msg->getArg(1)->getBeginLoc(),
  466. Msg->getArg(SentinelIdx - 1)->getEndLoc());
  467. commit.insertWrap("@{", ArgRange, "}");
  468. commit.replaceWithInner(MsgRange, ArgRange);
  469. return true;
  470. }
  471. if (Sel == NS.getNSDictionarySelector(
  472. NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
  473. Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
  474. if (Msg->getNumArgs() != 2)
  475. return false;
  476. SmallVector<const Expr *, 8> Vals;
  477. if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
  478. return false;
  479. SmallVector<const Expr *, 8> Keys;
  480. if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
  481. return false;
  482. if (Vals.size() != Keys.size())
  483. return false;
  484. if (Vals.empty()) {
  485. commit.replace(MsgRange, "@{}");
  486. return true;
  487. }
  488. for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
  489. objectifyExpr(Vals[i], commit);
  490. objectifyExpr(Keys[i], commit);
  491. SourceRange ValRange = Vals[i]->getSourceRange();
  492. SourceRange KeyRange = Keys[i]->getSourceRange();
  493. // Insert value after key.
  494. commit.insertAfterToken(KeyRange.getEnd(), ": ");
  495. commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
  496. }
  497. // Range of arguments up until and including the last key.
  498. // The first value is cut off, the value will move after the key.
  499. SourceRange ArgRange(Keys.front()->getBeginLoc(), Keys.back()->getEndLoc());
  500. commit.insertWrap("@{", ArgRange, "}");
  501. commit.replaceWithInner(MsgRange, ArgRange);
  502. return true;
  503. }
  504. return false;
  505. }
  506. static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
  507. const NSAPI &NS) {
  508. if (!Msg)
  509. return false;
  510. IdentifierInfo *II = nullptr;
  511. if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
  512. return false;
  513. if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
  514. return false;
  515. Selector Sel = Msg->getSelector();
  516. if (Sel == NS.getNSDictionarySelector(
  517. NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
  518. Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
  519. if (Msg->getNumArgs() != 2)
  520. return false;
  521. SmallVector<const Expr *, 8> Vals;
  522. if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
  523. return false;
  524. SmallVector<const Expr *, 8> Keys;
  525. if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
  526. return false;
  527. if (Vals.size() != Keys.size())
  528. return false;
  529. return true;
  530. }
  531. return false;
  532. }
  533. //===----------------------------------------------------------------------===//
  534. // rewriteToNumberLiteral.
  535. //===----------------------------------------------------------------------===//
  536. static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
  537. const CharacterLiteral *Arg,
  538. const NSAPI &NS, Commit &commit) {
  539. if (Arg->getKind() != CharacterLiteral::Ascii)
  540. return false;
  541. if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
  542. Msg->getSelector())) {
  543. SourceRange ArgRange = Arg->getSourceRange();
  544. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  545. commit.insert(ArgRange.getBegin(), "@");
  546. return true;
  547. }
  548. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  549. }
  550. static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
  551. const Expr *Arg,
  552. const NSAPI &NS, Commit &commit) {
  553. if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
  554. Msg->getSelector())) {
  555. SourceRange ArgRange = Arg->getSourceRange();
  556. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  557. commit.insert(ArgRange.getBegin(), "@");
  558. return true;
  559. }
  560. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  561. }
  562. namespace {
  563. struct LiteralInfo {
  564. bool Hex, Octal;
  565. StringRef U, F, L, LL;
  566. CharSourceRange WithoutSuffRange;
  567. };
  568. }
  569. static bool getLiteralInfo(SourceRange literalRange,
  570. bool isFloat, bool isIntZero,
  571. ASTContext &Ctx, LiteralInfo &Info) {
  572. if (literalRange.getBegin().isMacroID() ||
  573. literalRange.getEnd().isMacroID())
  574. return false;
  575. StringRef text = Lexer::getSourceText(
  576. CharSourceRange::getTokenRange(literalRange),
  577. Ctx.getSourceManager(), Ctx.getLangOpts());
  578. if (text.empty())
  579. return false;
  580. Optional<bool> UpperU, UpperL;
  581. bool UpperF = false;
  582. struct Suff {
  583. static bool has(StringRef suff, StringRef &text) {
  584. if (text.endswith(suff)) {
  585. text = text.substr(0, text.size()-suff.size());
  586. return true;
  587. }
  588. return false;
  589. }
  590. };
  591. while (1) {
  592. if (Suff::has("u", text)) {
  593. UpperU = false;
  594. } else if (Suff::has("U", text)) {
  595. UpperU = true;
  596. } else if (Suff::has("ll", text)) {
  597. UpperL = false;
  598. } else if (Suff::has("LL", text)) {
  599. UpperL = true;
  600. } else if (Suff::has("l", text)) {
  601. UpperL = false;
  602. } else if (Suff::has("L", text)) {
  603. UpperL = true;
  604. } else if (isFloat && Suff::has("f", text)) {
  605. UpperF = false;
  606. } else if (isFloat && Suff::has("F", text)) {
  607. UpperF = true;
  608. } else
  609. break;
  610. }
  611. if (!UpperU.hasValue() && !UpperL.hasValue())
  612. UpperU = UpperL = true;
  613. else if (UpperU.hasValue() && !UpperL.hasValue())
  614. UpperL = UpperU;
  615. else if (UpperL.hasValue() && !UpperU.hasValue())
  616. UpperU = UpperL;
  617. Info.U = *UpperU ? "U" : "u";
  618. Info.L = *UpperL ? "L" : "l";
  619. Info.LL = *UpperL ? "LL" : "ll";
  620. Info.F = UpperF ? "F" : "f";
  621. Info.Hex = Info.Octal = false;
  622. if (text.startswith("0x"))
  623. Info.Hex = true;
  624. else if (!isFloat && !isIntZero && text.startswith("0"))
  625. Info.Octal = true;
  626. SourceLocation B = literalRange.getBegin();
  627. Info.WithoutSuffRange =
  628. CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
  629. return true;
  630. }
  631. static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
  632. const NSAPI &NS, Commit &commit) {
  633. if (Msg->getNumArgs() != 1)
  634. return false;
  635. const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
  636. if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
  637. return rewriteToCharLiteral(Msg, CharE, NS, commit);
  638. if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
  639. return rewriteToBoolLiteral(Msg, BE, NS, commit);
  640. if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
  641. return rewriteToBoolLiteral(Msg, BE, NS, commit);
  642. const Expr *literalE = Arg;
  643. if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
  644. if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
  645. literalE = UOE->getSubExpr();
  646. }
  647. // Only integer and floating literals, otherwise try to rewrite to boxed
  648. // expression.
  649. if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
  650. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  651. ASTContext &Ctx = NS.getASTContext();
  652. Selector Sel = Msg->getSelector();
  653. Optional<NSAPI::NSNumberLiteralMethodKind>
  654. MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
  655. if (!MKOpt)
  656. return false;
  657. NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
  658. bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
  659. bool CallIsFloating = false, CallIsDouble = false;
  660. switch (MK) {
  661. // We cannot have these calls with int/float literals.
  662. case NSAPI::NSNumberWithChar:
  663. case NSAPI::NSNumberWithUnsignedChar:
  664. case NSAPI::NSNumberWithShort:
  665. case NSAPI::NSNumberWithUnsignedShort:
  666. case NSAPI::NSNumberWithBool:
  667. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  668. case NSAPI::NSNumberWithUnsignedInt:
  669. case NSAPI::NSNumberWithUnsignedInteger:
  670. CallIsUnsigned = true;
  671. LLVM_FALLTHROUGH;
  672. case NSAPI::NSNumberWithInt:
  673. case NSAPI::NSNumberWithInteger:
  674. break;
  675. case NSAPI::NSNumberWithUnsignedLong:
  676. CallIsUnsigned = true;
  677. LLVM_FALLTHROUGH;
  678. case NSAPI::NSNumberWithLong:
  679. CallIsLong = true;
  680. break;
  681. case NSAPI::NSNumberWithUnsignedLongLong:
  682. CallIsUnsigned = true;
  683. LLVM_FALLTHROUGH;
  684. case NSAPI::NSNumberWithLongLong:
  685. CallIsLongLong = true;
  686. break;
  687. case NSAPI::NSNumberWithDouble:
  688. CallIsDouble = true;
  689. LLVM_FALLTHROUGH;
  690. case NSAPI::NSNumberWithFloat:
  691. CallIsFloating = true;
  692. break;
  693. }
  694. SourceRange ArgRange = Arg->getSourceRange();
  695. QualType ArgTy = Arg->getType();
  696. QualType CallTy = Msg->getArg(0)->getType();
  697. // Check for the easy case, the literal maps directly to the call.
  698. if (Ctx.hasSameType(ArgTy, CallTy)) {
  699. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  700. commit.insert(ArgRange.getBegin(), "@");
  701. return true;
  702. }
  703. // We will need to modify the literal suffix to get the same type as the call.
  704. // Try with boxed expression if it came from a macro.
  705. if (ArgRange.getBegin().isMacroID())
  706. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  707. bool LitIsFloat = ArgTy->isFloatingType();
  708. // For a float passed to integer call, don't try rewriting to objc literal.
  709. // It is difficult and a very uncommon case anyway.
  710. // But try with boxed expression.
  711. if (LitIsFloat && !CallIsFloating)
  712. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  713. // Try to modify the literal make it the same type as the method call.
  714. // -Modify the suffix, and/or
  715. // -Change integer to float
  716. LiteralInfo LitInfo;
  717. bool isIntZero = false;
  718. if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
  719. isIntZero = !IntE->getValue().getBoolValue();
  720. if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
  721. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  722. // Not easy to do int -> float with hex/octal and uncommon anyway.
  723. if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
  724. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  725. SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
  726. SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
  727. commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
  728. LitInfo.WithoutSuffRange);
  729. commit.insert(LitB, "@");
  730. if (!LitIsFloat && CallIsFloating)
  731. commit.insert(LitE, ".0");
  732. if (CallIsFloating) {
  733. if (!CallIsDouble)
  734. commit.insert(LitE, LitInfo.F);
  735. } else {
  736. if (CallIsUnsigned)
  737. commit.insert(LitE, LitInfo.U);
  738. if (CallIsLong)
  739. commit.insert(LitE, LitInfo.L);
  740. else if (CallIsLongLong)
  741. commit.insert(LitE, LitInfo.LL);
  742. }
  743. return true;
  744. }
  745. // FIXME: Make determination of operator precedence more general and
  746. // make it broadly available.
  747. static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
  748. const Expr* Expr = FullExpr->IgnoreImpCasts();
  749. if (isa<ArraySubscriptExpr>(Expr) ||
  750. isa<CallExpr>(Expr) ||
  751. isa<DeclRefExpr>(Expr) ||
  752. isa<CXXNamedCastExpr>(Expr) ||
  753. isa<CXXConstructExpr>(Expr) ||
  754. isa<CXXThisExpr>(Expr) ||
  755. isa<CXXTypeidExpr>(Expr) ||
  756. isa<CXXUnresolvedConstructExpr>(Expr) ||
  757. isa<ObjCMessageExpr>(Expr) ||
  758. isa<ObjCPropertyRefExpr>(Expr) ||
  759. isa<ObjCProtocolExpr>(Expr) ||
  760. isa<MemberExpr>(Expr) ||
  761. isa<ObjCIvarRefExpr>(Expr) ||
  762. isa<ParenExpr>(FullExpr) ||
  763. isa<ParenListExpr>(Expr) ||
  764. isa<SizeOfPackExpr>(Expr))
  765. return false;
  766. return true;
  767. }
  768. static bool castOperatorNeedsParens(const Expr *FullExpr) {
  769. const Expr* Expr = FullExpr->IgnoreImpCasts();
  770. if (isa<ArraySubscriptExpr>(Expr) ||
  771. isa<CallExpr>(Expr) ||
  772. isa<DeclRefExpr>(Expr) ||
  773. isa<CastExpr>(Expr) ||
  774. isa<CXXNewExpr>(Expr) ||
  775. isa<CXXConstructExpr>(Expr) ||
  776. isa<CXXDeleteExpr>(Expr) ||
  777. isa<CXXNoexceptExpr>(Expr) ||
  778. isa<CXXPseudoDestructorExpr>(Expr) ||
  779. isa<CXXScalarValueInitExpr>(Expr) ||
  780. isa<CXXThisExpr>(Expr) ||
  781. isa<CXXTypeidExpr>(Expr) ||
  782. isa<CXXUnresolvedConstructExpr>(Expr) ||
  783. isa<ObjCMessageExpr>(Expr) ||
  784. isa<ObjCPropertyRefExpr>(Expr) ||
  785. isa<ObjCProtocolExpr>(Expr) ||
  786. isa<MemberExpr>(Expr) ||
  787. isa<ObjCIvarRefExpr>(Expr) ||
  788. isa<ParenExpr>(FullExpr) ||
  789. isa<ParenListExpr>(Expr) ||
  790. isa<SizeOfPackExpr>(Expr) ||
  791. isa<UnaryOperator>(Expr))
  792. return false;
  793. return true;
  794. }
  795. static void objectifyExpr(const Expr *E, Commit &commit) {
  796. if (!E) return;
  797. QualType T = E->getType();
  798. if (T->isObjCObjectPointerType()) {
  799. if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
  800. if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
  801. return;
  802. } else {
  803. return;
  804. }
  805. } else if (!T->isPointerType()) {
  806. return;
  807. }
  808. SourceRange Range = E->getSourceRange();
  809. if (castOperatorNeedsParens(E))
  810. commit.insertWrap("(", Range, ")");
  811. commit.insertBefore(Range.getBegin(), "(id)");
  812. }
  813. //===----------------------------------------------------------------------===//
  814. // rewriteToNumericBoxedExpression.
  815. //===----------------------------------------------------------------------===//
  816. static bool isEnumConstant(const Expr *E) {
  817. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
  818. if (const ValueDecl *VD = DRE->getDecl())
  819. return isa<EnumConstantDecl>(VD);
  820. return false;
  821. }
  822. static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
  823. const NSAPI &NS, Commit &commit) {
  824. if (Msg->getNumArgs() != 1)
  825. return false;
  826. const Expr *Arg = Msg->getArg(0);
  827. if (Arg->isTypeDependent())
  828. return false;
  829. ASTContext &Ctx = NS.getASTContext();
  830. Selector Sel = Msg->getSelector();
  831. Optional<NSAPI::NSNumberLiteralMethodKind>
  832. MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
  833. if (!MKOpt)
  834. return false;
  835. NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
  836. const Expr *OrigArg = Arg->IgnoreImpCasts();
  837. QualType FinalTy = Arg->getType();
  838. QualType OrigTy = OrigArg->getType();
  839. uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
  840. uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
  841. bool isTruncated = FinalTySize < OrigTySize;
  842. bool needsCast = false;
  843. if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
  844. switch (ICE->getCastKind()) {
  845. case CK_LValueToRValue:
  846. case CK_NoOp:
  847. case CK_UserDefinedConversion:
  848. break;
  849. case CK_IntegralCast: {
  850. if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
  851. break;
  852. // Be more liberal with Integer/UnsignedInteger which are very commonly
  853. // used.
  854. if ((MK == NSAPI::NSNumberWithInteger ||
  855. MK == NSAPI::NSNumberWithUnsignedInteger) &&
  856. !isTruncated) {
  857. if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
  858. break;
  859. if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
  860. OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
  861. break;
  862. }
  863. needsCast = true;
  864. break;
  865. }
  866. case CK_PointerToBoolean:
  867. case CK_IntegralToBoolean:
  868. case CK_IntegralToFloating:
  869. case CK_FloatingToIntegral:
  870. case CK_FloatingToBoolean:
  871. case CK_FloatingCast:
  872. case CK_FloatingComplexToReal:
  873. case CK_FloatingComplexToBoolean:
  874. case CK_IntegralComplexToReal:
  875. case CK_IntegralComplexToBoolean:
  876. case CK_AtomicToNonAtomic:
  877. case CK_AddressSpaceConversion:
  878. needsCast = true;
  879. break;
  880. case CK_Dependent:
  881. case CK_BitCast:
  882. case CK_LValueBitCast:
  883. case CK_LValueToRValueBitCast:
  884. case CK_BaseToDerived:
  885. case CK_DerivedToBase:
  886. case CK_UncheckedDerivedToBase:
  887. case CK_Dynamic:
  888. case CK_ToUnion:
  889. case CK_ArrayToPointerDecay:
  890. case CK_FunctionToPointerDecay:
  891. case CK_NullToPointer:
  892. case CK_NullToMemberPointer:
  893. case CK_BaseToDerivedMemberPointer:
  894. case CK_DerivedToBaseMemberPointer:
  895. case CK_MemberPointerToBoolean:
  896. case CK_ReinterpretMemberPointer:
  897. case CK_ConstructorConversion:
  898. case CK_IntegralToPointer:
  899. case CK_PointerToIntegral:
  900. case CK_ToVoid:
  901. case CK_VectorSplat:
  902. case CK_CPointerToObjCPointerCast:
  903. case CK_BlockPointerToObjCPointerCast:
  904. case CK_AnyPointerToBlockPointerCast:
  905. case CK_ObjCObjectLValueCast:
  906. case CK_FloatingRealToComplex:
  907. case CK_FloatingComplexCast:
  908. case CK_FloatingComplexToIntegralComplex:
  909. case CK_IntegralRealToComplex:
  910. case CK_IntegralComplexCast:
  911. case CK_IntegralComplexToFloatingComplex:
  912. case CK_ARCProduceObject:
  913. case CK_ARCConsumeObject:
  914. case CK_ARCReclaimReturnedObject:
  915. case CK_ARCExtendBlockObject:
  916. case CK_NonAtomicToAtomic:
  917. case CK_CopyAndAutoreleaseBlockObject:
  918. case CK_BuiltinFnToFnPtr:
  919. case CK_ZeroToOCLOpaqueType:
  920. case CK_IntToOCLSampler:
  921. return false;
  922. case CK_BooleanToSignedIntegral:
  923. llvm_unreachable("OpenCL-specific cast in Objective-C?");
  924. case CK_FixedPointCast:
  925. case CK_FixedPointToBoolean:
  926. case CK_FixedPointToIntegral:
  927. case CK_IntegralToFixedPoint:
  928. llvm_unreachable("Fixed point types are disabled for Objective-C");
  929. }
  930. }
  931. if (needsCast) {
  932. DiagnosticsEngine &Diags = Ctx.getDiagnostics();
  933. // FIXME: Use a custom category name to distinguish migration diagnostics.
  934. unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
  935. "converting to boxing syntax requires casting %0 to %1");
  936. Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
  937. << Msg->getSourceRange();
  938. return false;
  939. }
  940. SourceRange ArgRange = OrigArg->getSourceRange();
  941. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  942. if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
  943. commit.insertBefore(ArgRange.getBegin(), "@");
  944. else
  945. commit.insertWrap("@(", ArgRange, ")");
  946. return true;
  947. }
  948. //===----------------------------------------------------------------------===//
  949. // rewriteToStringBoxedExpression.
  950. //===----------------------------------------------------------------------===//
  951. static bool doRewriteToUTF8StringBoxedExpressionHelper(
  952. const ObjCMessageExpr *Msg,
  953. const NSAPI &NS, Commit &commit) {
  954. const Expr *Arg = Msg->getArg(0);
  955. if (Arg->isTypeDependent())
  956. return false;
  957. ASTContext &Ctx = NS.getASTContext();
  958. const Expr *OrigArg = Arg->IgnoreImpCasts();
  959. QualType OrigTy = OrigArg->getType();
  960. if (OrigTy->isArrayType())
  961. OrigTy = Ctx.getArrayDecayedType(OrigTy);
  962. if (const StringLiteral *
  963. StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
  964. commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
  965. commit.insert(StrE->getBeginLoc(), "@");
  966. return true;
  967. }
  968. if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
  969. QualType PointeeType = PT->getPointeeType();
  970. if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
  971. SourceRange ArgRange = OrigArg->getSourceRange();
  972. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  973. if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
  974. commit.insertBefore(ArgRange.getBegin(), "@");
  975. else
  976. commit.insertWrap("@(", ArgRange, ")");
  977. return true;
  978. }
  979. }
  980. return false;
  981. }
  982. static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
  983. const NSAPI &NS, Commit &commit) {
  984. Selector Sel = Msg->getSelector();
  985. if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
  986. Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString) ||
  987. Sel == NS.getNSStringSelector(NSAPI::NSStr_initWithUTF8String)) {
  988. if (Msg->getNumArgs() != 1)
  989. return false;
  990. return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
  991. }
  992. if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
  993. if (Msg->getNumArgs() != 2)
  994. return false;
  995. const Expr *encodingArg = Msg->getArg(1);
  996. if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
  997. NS.isNSASCIIStringEncodingConstant(encodingArg))
  998. return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
  999. }
  1000. return false;
  1001. }