RewriteObjCFoundationAPI.cpp 41 KB

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