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