RewriteObjCFoundationAPI.cpp 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247
  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 = 0;
  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 = 0;
  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. bool edit::rewriteToObjCProperty(const ObjCMethodDecl *Getter,
  302. const ObjCMethodDecl *Setter,
  303. const NSAPI &NS, Commit &commit) {
  304. ASTContext &Context = NS.getASTContext();
  305. std::string PropertyString = "@property";
  306. const ParmVarDecl *argDecl = *Setter->param_begin();
  307. QualType ArgType = Context.getCanonicalType(argDecl->getType());
  308. Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
  309. if (ArgType->isObjCRetainableType() &&
  310. propertyLifetime == Qualifiers::OCL_Strong) {
  311. if (const ObjCObjectPointerType *ObjPtrTy =
  312. ArgType->getAs<ObjCObjectPointerType>()) {
  313. ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
  314. if (IDecl &&
  315. IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
  316. PropertyString += "(copy)";
  317. }
  318. }
  319. else if (propertyLifetime == Qualifiers::OCL_Weak)
  320. // TODO. More precise determination of 'weak' attribute requires
  321. // looking into setter's implementation for backing weak ivar.
  322. PropertyString += "(weak)";
  323. else
  324. PropertyString += "(unsafe_unretained)";
  325. // strip off any ARC lifetime qualifier.
  326. QualType CanResultTy = Context.getCanonicalType(Getter->getResultType());
  327. if (CanResultTy.getQualifiers().hasObjCLifetime()) {
  328. Qualifiers Qs = CanResultTy.getQualifiers();
  329. Qs.removeObjCLifetime();
  330. CanResultTy = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
  331. }
  332. PropertyString += " ";
  333. PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy());
  334. PropertyString += " ";
  335. PropertyString += Getter->getNameAsString();
  336. commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
  337. Getter->getDeclaratorEndLoc()),
  338. PropertyString);
  339. SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
  340. // Get location past ';'
  341. EndLoc = EndLoc.getLocWithOffset(1);
  342. commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc));
  343. return true;
  344. }
  345. bool edit::rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
  346. llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
  347. const NSAPI &NS, Commit &commit) {
  348. const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
  349. std::string ClassString;
  350. SourceLocation EndLoc =
  351. IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
  352. if (Protocols.empty()) {
  353. ClassString = '<';
  354. for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
  355. ClassString += ConformingProtocols[i]->getNameAsString();
  356. if (i != (e-1))
  357. ClassString += ", ";
  358. }
  359. ClassString += "> ";
  360. }
  361. else {
  362. ClassString = ", ";
  363. for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
  364. ClassString += ConformingProtocols[i]->getNameAsString();
  365. if (i != (e-1))
  366. ClassString += ", ";
  367. }
  368. ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
  369. EndLoc = *PL;
  370. }
  371. commit.insertAfterToken(EndLoc, ClassString);
  372. return true;
  373. }
  374. /// \brief Returns true if the immediate message arguments of \c Msg should not
  375. /// be rewritten because it will interfere with the rewrite of the parent
  376. /// message expression. e.g.
  377. /// \code
  378. /// [NSDictionary dictionaryWithObjects:
  379. /// [NSArray arrayWithObjects:@"1", @"2", nil]
  380. /// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
  381. /// \endcode
  382. /// It will return true for this because we are going to rewrite this directly
  383. /// to a dictionary literal without any array literals.
  384. static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
  385. const NSAPI &NS);
  386. //===----------------------------------------------------------------------===//
  387. // rewriteToArrayLiteral.
  388. //===----------------------------------------------------------------------===//
  389. /// \brief Adds an explicit cast to 'id' if the type is not objc object.
  390. static void objectifyExpr(const Expr *E, Commit &commit);
  391. static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
  392. const NSAPI &NS, Commit &commit,
  393. const ParentMap *PMap) {
  394. if (PMap) {
  395. const ObjCMessageExpr *ParentMsg =
  396. dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
  397. if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
  398. return false;
  399. }
  400. Selector Sel = Msg->getSelector();
  401. SourceRange MsgRange = Msg->getSourceRange();
  402. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
  403. if (Msg->getNumArgs() != 0)
  404. return false;
  405. commit.replace(MsgRange, "@[]");
  406. return true;
  407. }
  408. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
  409. if (Msg->getNumArgs() != 1)
  410. return false;
  411. objectifyExpr(Msg->getArg(0), commit);
  412. SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
  413. commit.replaceWithInner(MsgRange, ArgRange);
  414. commit.insertWrap("@[", ArgRange, "]");
  415. return true;
  416. }
  417. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
  418. Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
  419. if (Msg->getNumArgs() == 0)
  420. return false;
  421. const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
  422. if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
  423. return false;
  424. for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
  425. objectifyExpr(Msg->getArg(i), commit);
  426. if (Msg->getNumArgs() == 1) {
  427. commit.replace(MsgRange, "@[]");
  428. return true;
  429. }
  430. SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
  431. Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
  432. commit.replaceWithInner(MsgRange, ArgRange);
  433. commit.insertWrap("@[", ArgRange, "]");
  434. return true;
  435. }
  436. return false;
  437. }
  438. //===----------------------------------------------------------------------===//
  439. // rewriteToDictionaryLiteral.
  440. //===----------------------------------------------------------------------===//
  441. /// \brief If \c Msg is an NSArray creation message or literal, this gets the
  442. /// objects that were used to create it.
  443. /// \returns true if it is an NSArray and we got objects, or false otherwise.
  444. static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
  445. SmallVectorImpl<const Expr *> &Objs) {
  446. if (!E)
  447. return false;
  448. E = E->IgnoreParenCasts();
  449. if (!E)
  450. return false;
  451. if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
  452. IdentifierInfo *Cls = 0;
  453. if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
  454. return false;
  455. if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
  456. return false;
  457. Selector Sel = Msg->getSelector();
  458. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
  459. return true; // empty array.
  460. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
  461. if (Msg->getNumArgs() != 1)
  462. return false;
  463. Objs.push_back(Msg->getArg(0));
  464. return true;
  465. }
  466. if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
  467. Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
  468. if (Msg->getNumArgs() == 0)
  469. return false;
  470. const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
  471. if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
  472. return false;
  473. for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
  474. Objs.push_back(Msg->getArg(i));
  475. return true;
  476. }
  477. } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
  478. for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
  479. Objs.push_back(ArrLit->getElement(i));
  480. return true;
  481. }
  482. return false;
  483. }
  484. static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
  485. const NSAPI &NS, Commit &commit) {
  486. Selector Sel = Msg->getSelector();
  487. SourceRange MsgRange = Msg->getSourceRange();
  488. if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
  489. if (Msg->getNumArgs() != 0)
  490. return false;
  491. commit.replace(MsgRange, "@{}");
  492. return true;
  493. }
  494. if (Sel == NS.getNSDictionarySelector(
  495. NSAPI::NSDict_dictionaryWithObjectForKey)) {
  496. if (Msg->getNumArgs() != 2)
  497. return false;
  498. objectifyExpr(Msg->getArg(0), commit);
  499. objectifyExpr(Msg->getArg(1), commit);
  500. SourceRange ValRange = Msg->getArg(0)->getSourceRange();
  501. SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
  502. // Insert key before the value.
  503. commit.insertBefore(ValRange.getBegin(), ": ");
  504. commit.insertFromRange(ValRange.getBegin(),
  505. CharSourceRange::getTokenRange(KeyRange),
  506. /*afterToken=*/false, /*beforePreviousInsertions=*/true);
  507. commit.insertBefore(ValRange.getBegin(), "@{");
  508. commit.insertAfterToken(ValRange.getEnd(), "}");
  509. commit.replaceWithInner(MsgRange, ValRange);
  510. return true;
  511. }
  512. if (Sel == NS.getNSDictionarySelector(
  513. NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
  514. Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
  515. if (Msg->getNumArgs() % 2 != 1)
  516. return false;
  517. unsigned SentinelIdx = Msg->getNumArgs() - 1;
  518. const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
  519. if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
  520. return false;
  521. if (Msg->getNumArgs() == 1) {
  522. commit.replace(MsgRange, "@{}");
  523. return true;
  524. }
  525. for (unsigned i = 0; i < SentinelIdx; i += 2) {
  526. objectifyExpr(Msg->getArg(i), commit);
  527. objectifyExpr(Msg->getArg(i+1), commit);
  528. SourceRange ValRange = Msg->getArg(i)->getSourceRange();
  529. SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
  530. // Insert value after key.
  531. commit.insertAfterToken(KeyRange.getEnd(), ": ");
  532. commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
  533. commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
  534. KeyRange.getBegin()));
  535. }
  536. // Range of arguments up until and including the last key.
  537. // The sentinel and first value are cut off, the value will move after the
  538. // key.
  539. SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
  540. Msg->getArg(SentinelIdx-1)->getLocEnd());
  541. commit.insertWrap("@{", ArgRange, "}");
  542. commit.replaceWithInner(MsgRange, ArgRange);
  543. return true;
  544. }
  545. if (Sel == NS.getNSDictionarySelector(
  546. NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
  547. Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
  548. if (Msg->getNumArgs() != 2)
  549. return false;
  550. SmallVector<const Expr *, 8> Vals;
  551. if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
  552. return false;
  553. SmallVector<const Expr *, 8> Keys;
  554. if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
  555. return false;
  556. if (Vals.size() != Keys.size())
  557. return false;
  558. if (Vals.empty()) {
  559. commit.replace(MsgRange, "@{}");
  560. return true;
  561. }
  562. for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
  563. objectifyExpr(Vals[i], commit);
  564. objectifyExpr(Keys[i], commit);
  565. SourceRange ValRange = Vals[i]->getSourceRange();
  566. SourceRange KeyRange = Keys[i]->getSourceRange();
  567. // Insert value after key.
  568. commit.insertAfterToken(KeyRange.getEnd(), ": ");
  569. commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
  570. }
  571. // Range of arguments up until and including the last key.
  572. // The first value is cut off, the value will move after the key.
  573. SourceRange ArgRange(Keys.front()->getLocStart(),
  574. Keys.back()->getLocEnd());
  575. commit.insertWrap("@{", ArgRange, "}");
  576. commit.replaceWithInner(MsgRange, ArgRange);
  577. return true;
  578. }
  579. return false;
  580. }
  581. static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
  582. const NSAPI &NS) {
  583. if (!Msg)
  584. return false;
  585. IdentifierInfo *II = 0;
  586. if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
  587. return false;
  588. if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
  589. return false;
  590. Selector Sel = Msg->getSelector();
  591. if (Sel == NS.getNSDictionarySelector(
  592. NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
  593. Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
  594. if (Msg->getNumArgs() != 2)
  595. return false;
  596. SmallVector<const Expr *, 8> Vals;
  597. if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
  598. return false;
  599. SmallVector<const Expr *, 8> Keys;
  600. if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
  601. return false;
  602. if (Vals.size() != Keys.size())
  603. return false;
  604. return true;
  605. }
  606. return false;
  607. }
  608. //===----------------------------------------------------------------------===//
  609. // rewriteToNumberLiteral.
  610. //===----------------------------------------------------------------------===//
  611. static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
  612. const CharacterLiteral *Arg,
  613. const NSAPI &NS, Commit &commit) {
  614. if (Arg->getKind() != CharacterLiteral::Ascii)
  615. return false;
  616. if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
  617. Msg->getSelector())) {
  618. SourceRange ArgRange = Arg->getSourceRange();
  619. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  620. commit.insert(ArgRange.getBegin(), "@");
  621. return true;
  622. }
  623. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  624. }
  625. static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
  626. const Expr *Arg,
  627. const NSAPI &NS, Commit &commit) {
  628. if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
  629. Msg->getSelector())) {
  630. SourceRange ArgRange = Arg->getSourceRange();
  631. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  632. commit.insert(ArgRange.getBegin(), "@");
  633. return true;
  634. }
  635. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  636. }
  637. namespace {
  638. struct LiteralInfo {
  639. bool Hex, Octal;
  640. StringRef U, F, L, LL;
  641. CharSourceRange WithoutSuffRange;
  642. };
  643. }
  644. static bool getLiteralInfo(SourceRange literalRange,
  645. bool isFloat, bool isIntZero,
  646. ASTContext &Ctx, LiteralInfo &Info) {
  647. if (literalRange.getBegin().isMacroID() ||
  648. literalRange.getEnd().isMacroID())
  649. return false;
  650. StringRef text = Lexer::getSourceText(
  651. CharSourceRange::getTokenRange(literalRange),
  652. Ctx.getSourceManager(), Ctx.getLangOpts());
  653. if (text.empty())
  654. return false;
  655. Optional<bool> UpperU, UpperL;
  656. bool UpperF = false;
  657. struct Suff {
  658. static bool has(StringRef suff, StringRef &text) {
  659. if (text.endswith(suff)) {
  660. text = text.substr(0, text.size()-suff.size());
  661. return true;
  662. }
  663. return false;
  664. }
  665. };
  666. while (1) {
  667. if (Suff::has("u", text)) {
  668. UpperU = false;
  669. } else if (Suff::has("U", text)) {
  670. UpperU = true;
  671. } else if (Suff::has("ll", text)) {
  672. UpperL = false;
  673. } else if (Suff::has("LL", text)) {
  674. UpperL = true;
  675. } else if (Suff::has("l", text)) {
  676. UpperL = false;
  677. } else if (Suff::has("L", text)) {
  678. UpperL = true;
  679. } else if (isFloat && Suff::has("f", text)) {
  680. UpperF = false;
  681. } else if (isFloat && Suff::has("F", text)) {
  682. UpperF = true;
  683. } else
  684. break;
  685. }
  686. if (!UpperU.hasValue() && !UpperL.hasValue())
  687. UpperU = UpperL = true;
  688. else if (UpperU.hasValue() && !UpperL.hasValue())
  689. UpperL = UpperU;
  690. else if (UpperL.hasValue() && !UpperU.hasValue())
  691. UpperU = UpperL;
  692. Info.U = *UpperU ? "U" : "u";
  693. Info.L = *UpperL ? "L" : "l";
  694. Info.LL = *UpperL ? "LL" : "ll";
  695. Info.F = UpperF ? "F" : "f";
  696. Info.Hex = Info.Octal = false;
  697. if (text.startswith("0x"))
  698. Info.Hex = true;
  699. else if (!isFloat && !isIntZero && text.startswith("0"))
  700. Info.Octal = true;
  701. SourceLocation B = literalRange.getBegin();
  702. Info.WithoutSuffRange =
  703. CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
  704. return true;
  705. }
  706. static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
  707. const NSAPI &NS, Commit &commit) {
  708. if (Msg->getNumArgs() != 1)
  709. return false;
  710. const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
  711. if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
  712. return rewriteToCharLiteral(Msg, CharE, NS, commit);
  713. if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
  714. return rewriteToBoolLiteral(Msg, BE, NS, commit);
  715. if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
  716. return rewriteToBoolLiteral(Msg, BE, NS, commit);
  717. const Expr *literalE = Arg;
  718. if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
  719. if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
  720. literalE = UOE->getSubExpr();
  721. }
  722. // Only integer and floating literals, otherwise try to rewrite to boxed
  723. // expression.
  724. if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
  725. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  726. ASTContext &Ctx = NS.getASTContext();
  727. Selector Sel = Msg->getSelector();
  728. Optional<NSAPI::NSNumberLiteralMethodKind>
  729. MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
  730. if (!MKOpt)
  731. return false;
  732. NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
  733. bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
  734. bool CallIsFloating = false, CallIsDouble = false;
  735. switch (MK) {
  736. // We cannot have these calls with int/float literals.
  737. case NSAPI::NSNumberWithChar:
  738. case NSAPI::NSNumberWithUnsignedChar:
  739. case NSAPI::NSNumberWithShort:
  740. case NSAPI::NSNumberWithUnsignedShort:
  741. case NSAPI::NSNumberWithBool:
  742. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  743. case NSAPI::NSNumberWithUnsignedInt:
  744. case NSAPI::NSNumberWithUnsignedInteger:
  745. CallIsUnsigned = true;
  746. case NSAPI::NSNumberWithInt:
  747. case NSAPI::NSNumberWithInteger:
  748. break;
  749. case NSAPI::NSNumberWithUnsignedLong:
  750. CallIsUnsigned = true;
  751. case NSAPI::NSNumberWithLong:
  752. CallIsLong = true;
  753. break;
  754. case NSAPI::NSNumberWithUnsignedLongLong:
  755. CallIsUnsigned = true;
  756. case NSAPI::NSNumberWithLongLong:
  757. CallIsLongLong = true;
  758. break;
  759. case NSAPI::NSNumberWithDouble:
  760. CallIsDouble = true;
  761. case NSAPI::NSNumberWithFloat:
  762. CallIsFloating = true;
  763. break;
  764. }
  765. SourceRange ArgRange = Arg->getSourceRange();
  766. QualType ArgTy = Arg->getType();
  767. QualType CallTy = Msg->getArg(0)->getType();
  768. // Check for the easy case, the literal maps directly to the call.
  769. if (Ctx.hasSameType(ArgTy, CallTy)) {
  770. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  771. commit.insert(ArgRange.getBegin(), "@");
  772. return true;
  773. }
  774. // We will need to modify the literal suffix to get the same type as the call.
  775. // Try with boxed expression if it came from a macro.
  776. if (ArgRange.getBegin().isMacroID())
  777. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  778. bool LitIsFloat = ArgTy->isFloatingType();
  779. // For a float passed to integer call, don't try rewriting to objc literal.
  780. // It is difficult and a very uncommon case anyway.
  781. // But try with boxed expression.
  782. if (LitIsFloat && !CallIsFloating)
  783. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  784. // Try to modify the literal make it the same type as the method call.
  785. // -Modify the suffix, and/or
  786. // -Change integer to float
  787. LiteralInfo LitInfo;
  788. bool isIntZero = false;
  789. if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
  790. isIntZero = !IntE->getValue().getBoolValue();
  791. if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
  792. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  793. // Not easy to do int -> float with hex/octal and uncommon anyway.
  794. if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
  795. return rewriteToNumericBoxedExpression(Msg, NS, commit);
  796. SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
  797. SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
  798. commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
  799. LitInfo.WithoutSuffRange);
  800. commit.insert(LitB, "@");
  801. if (!LitIsFloat && CallIsFloating)
  802. commit.insert(LitE, ".0");
  803. if (CallIsFloating) {
  804. if (!CallIsDouble)
  805. commit.insert(LitE, LitInfo.F);
  806. } else {
  807. if (CallIsUnsigned)
  808. commit.insert(LitE, LitInfo.U);
  809. if (CallIsLong)
  810. commit.insert(LitE, LitInfo.L);
  811. else if (CallIsLongLong)
  812. commit.insert(LitE, LitInfo.LL);
  813. }
  814. return true;
  815. }
  816. // FIXME: Make determination of operator precedence more general and
  817. // make it broadly available.
  818. static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
  819. const Expr* Expr = FullExpr->IgnoreImpCasts();
  820. if (isa<ArraySubscriptExpr>(Expr) ||
  821. isa<CallExpr>(Expr) ||
  822. isa<DeclRefExpr>(Expr) ||
  823. isa<CXXNamedCastExpr>(Expr) ||
  824. isa<CXXConstructExpr>(Expr) ||
  825. isa<CXXThisExpr>(Expr) ||
  826. isa<CXXTypeidExpr>(Expr) ||
  827. isa<CXXUnresolvedConstructExpr>(Expr) ||
  828. isa<ObjCMessageExpr>(Expr) ||
  829. isa<ObjCPropertyRefExpr>(Expr) ||
  830. isa<ObjCProtocolExpr>(Expr) ||
  831. isa<MemberExpr>(Expr) ||
  832. isa<ObjCIvarRefExpr>(Expr) ||
  833. isa<ParenExpr>(FullExpr) ||
  834. isa<ParenListExpr>(Expr) ||
  835. isa<SizeOfPackExpr>(Expr))
  836. return false;
  837. return true;
  838. }
  839. static bool castOperatorNeedsParens(const Expr *FullExpr) {
  840. const Expr* Expr = FullExpr->IgnoreImpCasts();
  841. if (isa<ArraySubscriptExpr>(Expr) ||
  842. isa<CallExpr>(Expr) ||
  843. isa<DeclRefExpr>(Expr) ||
  844. isa<CastExpr>(Expr) ||
  845. isa<CXXNewExpr>(Expr) ||
  846. isa<CXXConstructExpr>(Expr) ||
  847. isa<CXXDeleteExpr>(Expr) ||
  848. isa<CXXNoexceptExpr>(Expr) ||
  849. isa<CXXPseudoDestructorExpr>(Expr) ||
  850. isa<CXXScalarValueInitExpr>(Expr) ||
  851. isa<CXXThisExpr>(Expr) ||
  852. isa<CXXTypeidExpr>(Expr) ||
  853. isa<CXXUnresolvedConstructExpr>(Expr) ||
  854. isa<ObjCMessageExpr>(Expr) ||
  855. isa<ObjCPropertyRefExpr>(Expr) ||
  856. isa<ObjCProtocolExpr>(Expr) ||
  857. isa<MemberExpr>(Expr) ||
  858. isa<ObjCIvarRefExpr>(Expr) ||
  859. isa<ParenExpr>(FullExpr) ||
  860. isa<ParenListExpr>(Expr) ||
  861. isa<SizeOfPackExpr>(Expr) ||
  862. isa<UnaryOperator>(Expr))
  863. return false;
  864. return true;
  865. }
  866. static void objectifyExpr(const Expr *E, Commit &commit) {
  867. if (!E) return;
  868. QualType T = E->getType();
  869. if (T->isObjCObjectPointerType()) {
  870. if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
  871. if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
  872. return;
  873. } else {
  874. return;
  875. }
  876. } else if (!T->isPointerType()) {
  877. return;
  878. }
  879. SourceRange Range = E->getSourceRange();
  880. if (castOperatorNeedsParens(E))
  881. commit.insertWrap("(", Range, ")");
  882. commit.insertBefore(Range.getBegin(), "(id)");
  883. }
  884. //===----------------------------------------------------------------------===//
  885. // rewriteToNumericBoxedExpression.
  886. //===----------------------------------------------------------------------===//
  887. static bool isEnumConstant(const Expr *E) {
  888. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
  889. if (const ValueDecl *VD = DRE->getDecl())
  890. return isa<EnumConstantDecl>(VD);
  891. return false;
  892. }
  893. static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
  894. const NSAPI &NS, Commit &commit) {
  895. if (Msg->getNumArgs() != 1)
  896. return false;
  897. const Expr *Arg = Msg->getArg(0);
  898. if (Arg->isTypeDependent())
  899. return false;
  900. ASTContext &Ctx = NS.getASTContext();
  901. Selector Sel = Msg->getSelector();
  902. Optional<NSAPI::NSNumberLiteralMethodKind>
  903. MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
  904. if (!MKOpt)
  905. return false;
  906. NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
  907. const Expr *OrigArg = Arg->IgnoreImpCasts();
  908. QualType FinalTy = Arg->getType();
  909. QualType OrigTy = OrigArg->getType();
  910. uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
  911. uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
  912. bool isTruncated = FinalTySize < OrigTySize;
  913. bool needsCast = false;
  914. if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
  915. switch (ICE->getCastKind()) {
  916. case CK_LValueToRValue:
  917. case CK_NoOp:
  918. case CK_UserDefinedConversion:
  919. break;
  920. case CK_IntegralCast: {
  921. if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
  922. break;
  923. // Be more liberal with Integer/UnsignedInteger which are very commonly
  924. // used.
  925. if ((MK == NSAPI::NSNumberWithInteger ||
  926. MK == NSAPI::NSNumberWithUnsignedInteger) &&
  927. !isTruncated) {
  928. if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
  929. break;
  930. if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
  931. OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
  932. break;
  933. }
  934. needsCast = true;
  935. break;
  936. }
  937. case CK_PointerToBoolean:
  938. case CK_IntegralToBoolean:
  939. case CK_IntegralToFloating:
  940. case CK_FloatingToIntegral:
  941. case CK_FloatingToBoolean:
  942. case CK_FloatingCast:
  943. case CK_FloatingComplexToReal:
  944. case CK_FloatingComplexToBoolean:
  945. case CK_IntegralComplexToReal:
  946. case CK_IntegralComplexToBoolean:
  947. case CK_AtomicToNonAtomic:
  948. needsCast = true;
  949. break;
  950. case CK_Dependent:
  951. case CK_BitCast:
  952. case CK_LValueBitCast:
  953. case CK_BaseToDerived:
  954. case CK_DerivedToBase:
  955. case CK_UncheckedDerivedToBase:
  956. case CK_Dynamic:
  957. case CK_ToUnion:
  958. case CK_ArrayToPointerDecay:
  959. case CK_FunctionToPointerDecay:
  960. case CK_NullToPointer:
  961. case CK_NullToMemberPointer:
  962. case CK_BaseToDerivedMemberPointer:
  963. case CK_DerivedToBaseMemberPointer:
  964. case CK_MemberPointerToBoolean:
  965. case CK_ReinterpretMemberPointer:
  966. case CK_ConstructorConversion:
  967. case CK_IntegralToPointer:
  968. case CK_PointerToIntegral:
  969. case CK_ToVoid:
  970. case CK_VectorSplat:
  971. case CK_CPointerToObjCPointerCast:
  972. case CK_BlockPointerToObjCPointerCast:
  973. case CK_AnyPointerToBlockPointerCast:
  974. case CK_ObjCObjectLValueCast:
  975. case CK_FloatingRealToComplex:
  976. case CK_FloatingComplexCast:
  977. case CK_FloatingComplexToIntegralComplex:
  978. case CK_IntegralRealToComplex:
  979. case CK_IntegralComplexCast:
  980. case CK_IntegralComplexToFloatingComplex:
  981. case CK_ARCProduceObject:
  982. case CK_ARCConsumeObject:
  983. case CK_ARCReclaimReturnedObject:
  984. case CK_ARCExtendBlockObject:
  985. case CK_NonAtomicToAtomic:
  986. case CK_CopyAndAutoreleaseBlockObject:
  987. case CK_BuiltinFnToFnPtr:
  988. case CK_ZeroToOCLEvent:
  989. return false;
  990. }
  991. }
  992. if (needsCast) {
  993. DiagnosticsEngine &Diags = Ctx.getDiagnostics();
  994. // FIXME: Use a custom category name to distinguish migration diagnostics.
  995. unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
  996. "converting to boxing syntax requires casting %0 to %1");
  997. Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
  998. << Msg->getSourceRange();
  999. return false;
  1000. }
  1001. SourceRange ArgRange = OrigArg->getSourceRange();
  1002. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  1003. if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
  1004. commit.insertBefore(ArgRange.getBegin(), "@");
  1005. else
  1006. commit.insertWrap("@(", ArgRange, ")");
  1007. return true;
  1008. }
  1009. //===----------------------------------------------------------------------===//
  1010. // rewriteToStringBoxedExpression.
  1011. //===----------------------------------------------------------------------===//
  1012. static bool doRewriteToUTF8StringBoxedExpressionHelper(
  1013. const ObjCMessageExpr *Msg,
  1014. const NSAPI &NS, Commit &commit) {
  1015. const Expr *Arg = Msg->getArg(0);
  1016. if (Arg->isTypeDependent())
  1017. return false;
  1018. ASTContext &Ctx = NS.getASTContext();
  1019. const Expr *OrigArg = Arg->IgnoreImpCasts();
  1020. QualType OrigTy = OrigArg->getType();
  1021. if (OrigTy->isArrayType())
  1022. OrigTy = Ctx.getArrayDecayedType(OrigTy);
  1023. if (const StringLiteral *
  1024. StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
  1025. commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
  1026. commit.insert(StrE->getLocStart(), "@");
  1027. return true;
  1028. }
  1029. if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
  1030. QualType PointeeType = PT->getPointeeType();
  1031. if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
  1032. SourceRange ArgRange = OrigArg->getSourceRange();
  1033. commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
  1034. if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
  1035. commit.insertBefore(ArgRange.getBegin(), "@");
  1036. else
  1037. commit.insertWrap("@(", ArgRange, ")");
  1038. return true;
  1039. }
  1040. }
  1041. return false;
  1042. }
  1043. static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
  1044. const NSAPI &NS, Commit &commit) {
  1045. Selector Sel = Msg->getSelector();
  1046. if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
  1047. Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) {
  1048. if (Msg->getNumArgs() != 1)
  1049. return false;
  1050. return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
  1051. }
  1052. if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
  1053. if (Msg->getNumArgs() != 2)
  1054. return false;
  1055. const Expr *encodingArg = Msg->getArg(1);
  1056. if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
  1057. NS.isNSASCIIStringEncodingConstant(encodingArg))
  1058. return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
  1059. }
  1060. return false;
  1061. }