blob: 36704f66dcd7f9482f6f78d1266063e8a40cb7a7 [file] [log] [blame]
Ted Kremenekf7639e12012-03-06 20:06:33 +00001//===--- 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
14#include "clang/Edit/Rewriters.h"
15#include "clang/Edit/Commit.h"
16#include "clang/Lex/Lexer.h"
Benjamin Kramer1ea8e092012-07-04 17:04:04 +000017#include "clang/AST/ASTContext.h"
Ted Kremenekf7639e12012-03-06 20:06:33 +000018#include "clang/AST/ExprObjC.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/NSAPI.h"
21
22using namespace clang;
23using namespace edit;
24
25static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +000026 IdentifierInfo *&ClassId,
27 const LangOptions &LangOpts) {
Ted Kremenekf7639e12012-03-06 20:06:33 +000028 if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
29 return false;
30
31 const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
32 if (!Receiver)
33 return false;
34 ClassId = Receiver->getIdentifier();
35
36 if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
37 return true;
38
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +000039 // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
40 // since the change from +1 to +0 will be handled fine by ARC.
41 if (LangOpts.ObjCAutoRefCount) {
42 if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
43 if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
44 Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
45 if (Rec->getMethodFamily() == OMF_alloc)
46 return true;
47 }
48 }
49 }
50
Ted Kremenekf7639e12012-03-06 20:06:33 +000051 return false;
52}
53
54//===----------------------------------------------------------------------===//
55// rewriteObjCRedundantCallWithLiteral.
56//===----------------------------------------------------------------------===//
57
58bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
59 const NSAPI &NS, Commit &commit) {
60 IdentifierInfo *II = 0;
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +000061 if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
Ted Kremenekf7639e12012-03-06 20:06:33 +000062 return false;
63 if (Msg->getNumArgs() != 1)
64 return false;
65
66 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
67 Selector Sel = Msg->getSelector();
68
69 if ((isa<ObjCStringLiteral>(Arg) &&
70 NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +000071 (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
72 NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel)) ||
Ted Kremenekf7639e12012-03-06 20:06:33 +000073
74 (isa<ObjCArrayLiteral>(Arg) &&
75 NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +000076 (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
77 NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel)) ||
Ted Kremenekf7639e12012-03-06 20:06:33 +000078
79 (isa<ObjCDictionaryLiteral>(Arg) &&
80 NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +000081 (NS.getNSDictionarySelector(
82 NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
83 NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
Ted Kremenekf7639e12012-03-06 20:06:33 +000084
85 commit.replaceWithInner(Msg->getSourceRange(),
86 Msg->getArg(0)->getSourceRange());
87 return true;
88 }
89
90 return false;
91}
92
93//===----------------------------------------------------------------------===//
94// rewriteToObjCSubscriptSyntax.
95//===----------------------------------------------------------------------===//
96
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +000097static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *IFace,
98 Selector subscriptSel) {
99 if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
100 if (!MD->isUnavailable())
101 return true;
102 }
103 return false;
104}
105
Argyrios Kyrtzidis0bbe94f2012-05-14 23:33:49 +0000106static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
107
Ted Kremenekf7639e12012-03-06 20:06:33 +0000108static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
Argyrios Kyrtzidis0bbe94f2012-05-14 23:33:49 +0000109 if (subscriptOperatorNeedsParens(Receiver)) {
Ted Kremenekf7639e12012-03-06 20:06:33 +0000110 SourceRange RecRange = Receiver->getSourceRange();
111 commit.insertWrap("(", RecRange, ")");
112 }
113}
114
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000115static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
116 Commit &commit) {
Ted Kremenekf7639e12012-03-06 20:06:33 +0000117 if (Msg->getNumArgs() != 1)
118 return false;
119 const Expr *Rec = Msg->getInstanceReceiver();
120 if (!Rec)
121 return false;
122
123 SourceRange MsgRange = Msg->getSourceRange();
124 SourceRange RecRange = Rec->getSourceRange();
125 SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
126
127 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
128 ArgRange.getBegin()),
129 CharSourceRange::getTokenRange(RecRange));
130 commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
131 ArgRange);
132 commit.insertWrap("[", ArgRange, "]");
133 maybePutParensOnReceiver(Rec, commit);
134 return true;
135}
136
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000137static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
138 const ObjCMessageExpr *Msg,
139 const NSAPI &NS,
140 Commit &commit) {
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000141 if (!canRewriteToSubscriptSyntax(IFace,
142 NS.getObjectAtIndexedSubscriptSelector()))
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000143 return false;
144 return rewriteToSubscriptGetCommon(Msg, commit);
145}
146
147static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
148 const ObjCMessageExpr *Msg,
149 const NSAPI &NS,
150 Commit &commit) {
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000151 if (!canRewriteToSubscriptSyntax(IFace,
152 NS.getObjectForKeyedSubscriptSelector()))
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000153 return false;
154 return rewriteToSubscriptGetCommon(Msg, commit);
155}
156
157static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
158 const ObjCMessageExpr *Msg,
159 const NSAPI &NS,
Ted Kremenekf7639e12012-03-06 20:06:33 +0000160 Commit &commit) {
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000161 if (!canRewriteToSubscriptSyntax(IFace,
162 NS.getSetObjectAtIndexedSubscriptSelector()))
163 return false;
164
Ted Kremenekf7639e12012-03-06 20:06:33 +0000165 if (Msg->getNumArgs() != 2)
166 return false;
167 const Expr *Rec = Msg->getInstanceReceiver();
168 if (!Rec)
169 return false;
170
171 SourceRange MsgRange = Msg->getSourceRange();
172 SourceRange RecRange = Rec->getSourceRange();
173 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
174 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
175
176 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
177 Arg0Range.getBegin()),
178 CharSourceRange::getTokenRange(RecRange));
179 commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
180 Arg1Range.getBegin()),
181 CharSourceRange::getTokenRange(Arg0Range));
182 commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
183 Arg1Range);
184 commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
185 Arg1Range.getBegin()),
186 "] = ");
187 maybePutParensOnReceiver(Rec, commit);
188 return true;
189}
190
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000191static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
192 const ObjCMessageExpr *Msg,
193 const NSAPI &NS,
Ted Kremenekf7639e12012-03-06 20:06:33 +0000194 Commit &commit) {
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000195 if (!canRewriteToSubscriptSyntax(IFace,
196 NS.getSetObjectForKeyedSubscriptSelector()))
197 return false;
198
Ted Kremenekf7639e12012-03-06 20:06:33 +0000199 if (Msg->getNumArgs() != 2)
200 return false;
201 const Expr *Rec = Msg->getInstanceReceiver();
202 if (!Rec)
203 return false;
204
205 SourceRange MsgRange = Msg->getSourceRange();
206 SourceRange RecRange = Rec->getSourceRange();
207 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
208 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
209
210 SourceLocation LocBeforeVal = Arg0Range.getBegin();
211 commit.insertBefore(LocBeforeVal, "] = ");
212 commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
213 /*beforePreviousInsertions=*/true);
214 commit.insertBefore(LocBeforeVal, "[");
215 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
216 Arg0Range.getBegin()),
217 CharSourceRange::getTokenRange(RecRange));
218 commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
219 Arg0Range);
220 maybePutParensOnReceiver(Rec, commit);
221 return true;
222}
223
224bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000225 const NSAPI &NS, Commit &commit) {
Ted Kremenekf7639e12012-03-06 20:06:33 +0000226 if (!Msg || Msg->isImplicit() ||
227 Msg->getReceiverKind() != ObjCMessageExpr::Instance)
228 return false;
229 const ObjCMethodDecl *Method = Msg->getMethodDecl();
230 if (!Method)
231 return false;
232
233 const ObjCInterfaceDecl *
234 IFace = NS.getASTContext().getObjContainingInterface(
235 const_cast<ObjCMethodDecl *>(Method));
236 if (!IFace)
237 return false;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000238 Selector Sel = Msg->getSelector();
239
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000240 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000241 return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
242
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000243 if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000244 return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000245
246 if (Msg->getNumArgs() != 2)
247 return false;
248
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000249 if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000250 return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000251
Argyrios Kyrtzidis13b92922012-07-05 21:49:51 +0000252 if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
Argyrios Kyrtzidis6310fdd2012-06-04 21:23:26 +0000253 return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000254
255 return false;
256}
257
258//===----------------------------------------------------------------------===//
259// rewriteToObjCLiteralSyntax.
260//===----------------------------------------------------------------------===//
261
262static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
263 const NSAPI &NS, Commit &commit);
264static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
265 const NSAPI &NS, Commit &commit);
266static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
267 const NSAPI &NS, Commit &commit);
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000268static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
269 const NSAPI &NS, Commit &commit);
Argyrios Kyrtzidis7bd957c2012-05-15 22:22:10 +0000270static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
271 const NSAPI &NS, Commit &commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000272
273bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
274 const NSAPI &NS, Commit &commit) {
275 IdentifierInfo *II = 0;
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +0000276 if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
Ted Kremenekf7639e12012-03-06 20:06:33 +0000277 return false;
278
279 if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
280 return rewriteToArrayLiteral(Msg, NS, commit);
281 if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
282 return rewriteToDictionaryLiteral(Msg, NS, commit);
283 if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
284 return rewriteToNumberLiteral(Msg, NS, commit);
Argyrios Kyrtzidis7bd957c2012-05-15 22:22:10 +0000285 if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
286 return rewriteToStringBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000287
288 return false;
289}
290
291//===----------------------------------------------------------------------===//
292// rewriteToArrayLiteral.
293//===----------------------------------------------------------------------===//
294
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000295/// \brief Adds an explicit cast to 'id' if the type is not objc object.
296static void objectifyExpr(const Expr *E, Commit &commit);
297
Ted Kremenekf7639e12012-03-06 20:06:33 +0000298static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
299 const NSAPI &NS, Commit &commit) {
300 Selector Sel = Msg->getSelector();
301 SourceRange MsgRange = Msg->getSourceRange();
302
303 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
304 if (Msg->getNumArgs() != 0)
305 return false;
306 commit.replace(MsgRange, "@[]");
307 return true;
308 }
309
310 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
311 if (Msg->getNumArgs() != 1)
312 return false;
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000313 objectifyExpr(Msg->getArg(0), commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000314 SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
315 commit.replaceWithInner(MsgRange, ArgRange);
316 commit.insertWrap("@[", ArgRange, "]");
317 return true;
318 }
319
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +0000320 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
321 Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
Ted Kremenekf7639e12012-03-06 20:06:33 +0000322 if (Msg->getNumArgs() == 0)
323 return false;
324 const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
325 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
326 return false;
327
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000328 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
329 objectifyExpr(Msg->getArg(i), commit);
330
Ted Kremenekf7639e12012-03-06 20:06:33 +0000331 if (Msg->getNumArgs() == 1) {
332 commit.replace(MsgRange, "@[]");
333 return true;
334 }
335 SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
336 Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
337 commit.replaceWithInner(MsgRange, ArgRange);
338 commit.insertWrap("@[", ArgRange, "]");
339 return true;
340 }
341
342 return false;
343}
344
345//===----------------------------------------------------------------------===//
346// rewriteToDictionaryLiteral.
347//===----------------------------------------------------------------------===//
348
349static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
350 const NSAPI &NS, Commit &commit) {
351 Selector Sel = Msg->getSelector();
352 SourceRange MsgRange = Msg->getSourceRange();
353
354 if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
355 if (Msg->getNumArgs() != 0)
356 return false;
357 commit.replace(MsgRange, "@{}");
358 return true;
359 }
360
361 if (Sel == NS.getNSDictionarySelector(
362 NSAPI::NSDict_dictionaryWithObjectForKey)) {
363 if (Msg->getNumArgs() != 2)
364 return false;
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000365
366 objectifyExpr(Msg->getArg(0), commit);
367 objectifyExpr(Msg->getArg(1), commit);
368
Ted Kremenekf7639e12012-03-06 20:06:33 +0000369 SourceRange ValRange = Msg->getArg(0)->getSourceRange();
370 SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
371 // Insert key before the value.
372 commit.insertBefore(ValRange.getBegin(), ": ");
373 commit.insertFromRange(ValRange.getBegin(),
374 CharSourceRange::getTokenRange(KeyRange),
375 /*afterToken=*/false, /*beforePreviousInsertions=*/true);
376 commit.insertBefore(ValRange.getBegin(), "@{");
377 commit.insertAfterToken(ValRange.getEnd(), "}");
378 commit.replaceWithInner(MsgRange, ValRange);
379 return true;
380 }
381
382 if (Sel == NS.getNSDictionarySelector(
Argyrios Kyrtzidis63aebfb2012-06-06 22:23:12 +0000383 NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
384 Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
Ted Kremenekf7639e12012-03-06 20:06:33 +0000385 if (Msg->getNumArgs() % 2 != 1)
386 return false;
387 unsigned SentinelIdx = Msg->getNumArgs() - 1;
388 const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
389 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
390 return false;
391
392 if (Msg->getNumArgs() == 1) {
393 commit.replace(MsgRange, "@{}");
394 return true;
395 }
396
397 for (unsigned i = 0; i < SentinelIdx; i += 2) {
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000398 objectifyExpr(Msg->getArg(i), commit);
399 objectifyExpr(Msg->getArg(i+1), commit);
400
Ted Kremenekf7639e12012-03-06 20:06:33 +0000401 SourceRange ValRange = Msg->getArg(i)->getSourceRange();
402 SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
403 // Insert value after key.
404 commit.insertAfterToken(KeyRange.getEnd(), ": ");
405 commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
406 commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
407 KeyRange.getBegin()));
408 }
409 // Range of arguments up until and including the last key.
410 // The sentinel and first value are cut off, the value will move after the
411 // key.
412 SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
413 Msg->getArg(SentinelIdx-1)->getLocEnd());
414 commit.insertWrap("@{", ArgRange, "}");
415 commit.replaceWithInner(MsgRange, ArgRange);
416 return true;
417 }
418
419 return false;
420}
421
422//===----------------------------------------------------------------------===//
423// rewriteToNumberLiteral.
424//===----------------------------------------------------------------------===//
425
426static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
427 const CharacterLiteral *Arg,
428 const NSAPI &NS, Commit &commit) {
429 if (Arg->getKind() != CharacterLiteral::Ascii)
430 return false;
431 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
432 Msg->getSelector())) {
433 SourceRange ArgRange = Arg->getSourceRange();
434 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
435 commit.insert(ArgRange.getBegin(), "@");
436 return true;
437 }
438
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000439 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000440}
441
442static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
443 const Expr *Arg,
444 const NSAPI &NS, Commit &commit) {
445 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
446 Msg->getSelector())) {
447 SourceRange ArgRange = Arg->getSourceRange();
448 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
449 commit.insert(ArgRange.getBegin(), "@");
450 return true;
451 }
452
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000453 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000454}
455
456namespace {
457
458struct LiteralInfo {
459 bool Hex, Octal;
460 StringRef U, F, L, LL;
461 CharSourceRange WithoutSuffRange;
462};
463
464}
465
466static bool getLiteralInfo(SourceRange literalRange,
467 bool isFloat, bool isIntZero,
468 ASTContext &Ctx, LiteralInfo &Info) {
469 if (literalRange.getBegin().isMacroID() ||
470 literalRange.getEnd().isMacroID())
471 return false;
472 StringRef text = Lexer::getSourceText(
473 CharSourceRange::getTokenRange(literalRange),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000474 Ctx.getSourceManager(), Ctx.getLangOpts());
Ted Kremenekf7639e12012-03-06 20:06:33 +0000475 if (text.empty())
476 return false;
477
478 llvm::Optional<bool> UpperU, UpperL;
479 bool UpperF = false;
480
481 struct Suff {
482 static bool has(StringRef suff, StringRef &text) {
483 if (text.endswith(suff)) {
484 text = text.substr(0, text.size()-suff.size());
485 return true;
486 }
487 return false;
488 }
489 };
490
491 while (1) {
492 if (Suff::has("u", text)) {
493 UpperU = false;
494 } else if (Suff::has("U", text)) {
495 UpperU = true;
496 } else if (Suff::has("ll", text)) {
497 UpperL = false;
498 } else if (Suff::has("LL", text)) {
499 UpperL = true;
500 } else if (Suff::has("l", text)) {
501 UpperL = false;
502 } else if (Suff::has("L", text)) {
503 UpperL = true;
504 } else if (isFloat && Suff::has("f", text)) {
505 UpperF = false;
506 } else if (isFloat && Suff::has("F", text)) {
507 UpperF = true;
508 } else
509 break;
510 }
511
512 if (!UpperU.hasValue() && !UpperL.hasValue())
513 UpperU = UpperL = true;
514 else if (UpperU.hasValue() && !UpperL.hasValue())
515 UpperL = UpperU;
516 else if (UpperL.hasValue() && !UpperU.hasValue())
517 UpperU = UpperL;
518
519 Info.U = *UpperU ? "U" : "u";
520 Info.L = *UpperL ? "L" : "l";
521 Info.LL = *UpperL ? "LL" : "ll";
522 Info.F = UpperF ? "F" : "f";
523
524 Info.Hex = Info.Octal = false;
525 if (text.startswith("0x"))
526 Info.Hex = true;
527 else if (!isFloat && !isIntZero && text.startswith("0"))
528 Info.Octal = true;
529
530 SourceLocation B = literalRange.getBegin();
531 Info.WithoutSuffRange =
532 CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
533 return true;
534}
535
536static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
537 const NSAPI &NS, Commit &commit) {
538 if (Msg->getNumArgs() != 1)
539 return false;
540
541 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
542 if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
543 return rewriteToCharLiteral(Msg, CharE, NS, commit);
544 if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
545 return rewriteToBoolLiteral(Msg, BE, NS, commit);
546 if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
547 return rewriteToBoolLiteral(Msg, BE, NS, commit);
548
549 const Expr *literalE = Arg;
550 if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
551 if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
552 literalE = UOE->getSubExpr();
553 }
554
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000555 // Only integer and floating literals, otherwise try to rewrite to boxed
556 // expression.
Ted Kremenekf7639e12012-03-06 20:06:33 +0000557 if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000558 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000559
560 ASTContext &Ctx = NS.getASTContext();
561 Selector Sel = Msg->getSelector();
562 llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
563 MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
564 if (!MKOpt)
565 return false;
566 NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
567
Benjamin Kramerece209a2012-03-13 17:05:43 +0000568 bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000569 bool CallIsFloating = false, CallIsDouble = false;
570
571 switch (MK) {
572 // We cannot have these calls with int/float literals.
573 case NSAPI::NSNumberWithChar:
574 case NSAPI::NSNumberWithUnsignedChar:
575 case NSAPI::NSNumberWithShort:
576 case NSAPI::NSNumberWithUnsignedShort:
577 case NSAPI::NSNumberWithBool:
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000578 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000579
580 case NSAPI::NSNumberWithUnsignedInt:
581 case NSAPI::NSNumberWithUnsignedInteger:
582 CallIsUnsigned = true;
583 case NSAPI::NSNumberWithInt:
584 case NSAPI::NSNumberWithInteger:
Ted Kremenekf7639e12012-03-06 20:06:33 +0000585 break;
586
587 case NSAPI::NSNumberWithUnsignedLong:
588 CallIsUnsigned = true;
589 case NSAPI::NSNumberWithLong:
Benjamin Kramerece209a2012-03-13 17:05:43 +0000590 CallIsLong = true;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000591 break;
592
593 case NSAPI::NSNumberWithUnsignedLongLong:
594 CallIsUnsigned = true;
595 case NSAPI::NSNumberWithLongLong:
Benjamin Kramerece209a2012-03-13 17:05:43 +0000596 CallIsLongLong = true;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000597 break;
598
599 case NSAPI::NSNumberWithDouble:
600 CallIsDouble = true;
601 case NSAPI::NSNumberWithFloat:
602 CallIsFloating = true;
603 break;
604 }
605
606 SourceRange ArgRange = Arg->getSourceRange();
607 QualType ArgTy = Arg->getType();
608 QualType CallTy = Msg->getArg(0)->getType();
609
610 // Check for the easy case, the literal maps directly to the call.
611 if (Ctx.hasSameType(ArgTy, CallTy)) {
612 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
613 commit.insert(ArgRange.getBegin(), "@");
614 return true;
615 }
616
617 // We will need to modify the literal suffix to get the same type as the call.
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000618 // Try with boxed expression if it came from a macro.
Ted Kremenekf7639e12012-03-06 20:06:33 +0000619 if (ArgRange.getBegin().isMacroID())
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000620 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000621
622 bool LitIsFloat = ArgTy->isFloatingType();
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000623 // For a float passed to integer call, don't try rewriting to objc literal.
624 // It is difficult and a very uncommon case anyway.
625 // But try with boxed expression.
Ted Kremenekf7639e12012-03-06 20:06:33 +0000626 if (LitIsFloat && !CallIsFloating)
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000627 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000628
629 // Try to modify the literal make it the same type as the method call.
630 // -Modify the suffix, and/or
631 // -Change integer to float
632
633 LiteralInfo LitInfo;
634 bool isIntZero = false;
635 if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
636 isIntZero = !IntE->getValue().getBoolValue();
637 if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000638 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000639
640 // Not easy to do int -> float with hex/octal and uncommon anyway.
641 if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000642 return rewriteToNumericBoxedExpression(Msg, NS, commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000643
644 SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
645 SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
646
647 commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
648 LitInfo.WithoutSuffRange);
649 commit.insert(LitB, "@");
650
651 if (!LitIsFloat && CallIsFloating)
652 commit.insert(LitE, ".0");
653
654 if (CallIsFloating) {
655 if (!CallIsDouble)
656 commit.insert(LitE, LitInfo.F);
657 } else {
658 if (CallIsUnsigned)
659 commit.insert(LitE, LitInfo.U);
660
661 if (CallIsLong)
662 commit.insert(LitE, LitInfo.L);
663 else if (CallIsLongLong)
664 commit.insert(LitE, LitInfo.LL);
665 }
666 return true;
667}
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000668
Argyrios Kyrtzidis0bbe94f2012-05-14 23:33:49 +0000669// FIXME: Make determination of operator precedence more general and
670// make it broadly available.
671static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
672 const Expr* Expr = FullExpr->IgnoreImpCasts();
673 if (isa<ArraySubscriptExpr>(Expr) ||
674 isa<CallExpr>(Expr) ||
675 isa<DeclRefExpr>(Expr) ||
676 isa<CXXNamedCastExpr>(Expr) ||
677 isa<CXXConstructExpr>(Expr) ||
678 isa<CXXThisExpr>(Expr) ||
679 isa<CXXTypeidExpr>(Expr) ||
680 isa<CXXUnresolvedConstructExpr>(Expr) ||
681 isa<ObjCMessageExpr>(Expr) ||
682 isa<ObjCPropertyRefExpr>(Expr) ||
683 isa<ObjCProtocolExpr>(Expr) ||
684 isa<MemberExpr>(Expr) ||
Argyrios Kyrtzidis94442982012-05-22 00:47:53 +0000685 isa<ObjCIvarRefExpr>(Expr) ||
Argyrios Kyrtzidis0bbe94f2012-05-14 23:33:49 +0000686 isa<ParenExpr>(FullExpr) ||
687 isa<ParenListExpr>(Expr) ||
688 isa<SizeOfPackExpr>(Expr))
689 return false;
690
691 return true;
692}
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000693static bool castOperatorNeedsParens(const Expr *FullExpr) {
694 const Expr* Expr = FullExpr->IgnoreImpCasts();
695 if (isa<ArraySubscriptExpr>(Expr) ||
696 isa<CallExpr>(Expr) ||
697 isa<DeclRefExpr>(Expr) ||
698 isa<CastExpr>(Expr) ||
699 isa<CXXNewExpr>(Expr) ||
700 isa<CXXConstructExpr>(Expr) ||
701 isa<CXXDeleteExpr>(Expr) ||
702 isa<CXXNoexceptExpr>(Expr) ||
703 isa<CXXPseudoDestructorExpr>(Expr) ||
704 isa<CXXScalarValueInitExpr>(Expr) ||
705 isa<CXXThisExpr>(Expr) ||
706 isa<CXXTypeidExpr>(Expr) ||
707 isa<CXXUnresolvedConstructExpr>(Expr) ||
708 isa<ObjCMessageExpr>(Expr) ||
709 isa<ObjCPropertyRefExpr>(Expr) ||
710 isa<ObjCProtocolExpr>(Expr) ||
711 isa<MemberExpr>(Expr) ||
Argyrios Kyrtzidis94442982012-05-22 00:47:53 +0000712 isa<ObjCIvarRefExpr>(Expr) ||
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000713 isa<ParenExpr>(FullExpr) ||
714 isa<ParenListExpr>(Expr) ||
715 isa<SizeOfPackExpr>(Expr) ||
716 isa<UnaryOperator>(Expr))
717 return false;
718
719 return true;
720}
721
722static void objectifyExpr(const Expr *E, Commit &commit) {
723 if (!E) return;
724
725 QualType T = E->getType();
726 if (T->isObjCObjectPointerType()) {
727 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
728 if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
729 return;
730 } else {
731 return;
732 }
733 } else if (!T->isPointerType()) {
734 return;
735 }
736
737 SourceRange Range = E->getSourceRange();
738 if (castOperatorNeedsParens(E))
739 commit.insertWrap("(", Range, ")");
740 commit.insertBefore(Range.getBegin(), "(id)");
741}
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000742
743//===----------------------------------------------------------------------===//
744// rewriteToNumericBoxedExpression.
745//===----------------------------------------------------------------------===//
746
Argyrios Kyrtzidiscebe7222012-05-15 22:59:54 +0000747static bool isEnumConstant(const Expr *E) {
748 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
749 if (const ValueDecl *VD = DRE->getDecl())
750 return isa<EnumConstantDecl>(VD);
751
752 return false;
753}
754
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000755static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
756 const NSAPI &NS, Commit &commit) {
757 if (Msg->getNumArgs() != 1)
758 return false;
759
760 const Expr *Arg = Msg->getArg(0);
761 if (Arg->isTypeDependent())
762 return false;
763
764 ASTContext &Ctx = NS.getASTContext();
765 Selector Sel = Msg->getSelector();
766 llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
767 MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
768 if (!MKOpt)
769 return false;
770 NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
771
772 const Expr *OrigArg = Arg->IgnoreImpCasts();
773 QualType FinalTy = Arg->getType();
774 QualType OrigTy = OrigArg->getType();
775 uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
776 uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
777
778 bool isTruncated = FinalTySize < OrigTySize;
779 bool needsCast = false;
780
781 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
782 switch (ICE->getCastKind()) {
783 case CK_LValueToRValue:
784 case CK_NoOp:
785 case CK_UserDefinedConversion:
786 break;
787
788 case CK_IntegralCast: {
789 if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
790 break;
791 // Be more liberal with Integer/UnsignedInteger which are very commonly
792 // used.
793 if ((MK == NSAPI::NSNumberWithInteger ||
794 MK == NSAPI::NSNumberWithUnsignedInteger) &&
795 !isTruncated) {
Argyrios Kyrtzidiscebe7222012-05-15 22:59:54 +0000796 if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000797 break;
798 if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
799 OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
800 break;
801 }
802
803 needsCast = true;
804 break;
805 }
806
807 case CK_PointerToBoolean:
808 case CK_IntegralToBoolean:
809 case CK_IntegralToFloating:
810 case CK_FloatingToIntegral:
811 case CK_FloatingToBoolean:
812 case CK_FloatingCast:
813 case CK_FloatingComplexToReal:
814 case CK_FloatingComplexToBoolean:
815 case CK_IntegralComplexToReal:
816 case CK_IntegralComplexToBoolean:
817 case CK_AtomicToNonAtomic:
818 needsCast = true;
819 break;
820
821 case CK_Dependent:
822 case CK_BitCast:
823 case CK_LValueBitCast:
824 case CK_BaseToDerived:
825 case CK_DerivedToBase:
826 case CK_UncheckedDerivedToBase:
827 case CK_Dynamic:
828 case CK_ToUnion:
829 case CK_ArrayToPointerDecay:
830 case CK_FunctionToPointerDecay:
831 case CK_NullToPointer:
832 case CK_NullToMemberPointer:
833 case CK_BaseToDerivedMemberPointer:
834 case CK_DerivedToBaseMemberPointer:
835 case CK_MemberPointerToBoolean:
836 case CK_ReinterpretMemberPointer:
837 case CK_ConstructorConversion:
838 case CK_IntegralToPointer:
839 case CK_PointerToIntegral:
840 case CK_ToVoid:
841 case CK_VectorSplat:
842 case CK_CPointerToObjCPointerCast:
843 case CK_BlockPointerToObjCPointerCast:
844 case CK_AnyPointerToBlockPointerCast:
845 case CK_ObjCObjectLValueCast:
846 case CK_FloatingRealToComplex:
847 case CK_FloatingComplexCast:
848 case CK_FloatingComplexToIntegralComplex:
849 case CK_IntegralRealToComplex:
850 case CK_IntegralComplexCast:
851 case CK_IntegralComplexToFloatingComplex:
852 case CK_ARCProduceObject:
853 case CK_ARCConsumeObject:
854 case CK_ARCReclaimReturnedObject:
855 case CK_ARCExtendBlockObject:
856 case CK_NonAtomicToAtomic:
857 case CK_CopyAndAutoreleaseBlockObject:
858 return false;
859 }
860 }
861
Argyrios Kyrtzidisb4822602012-05-24 16:48:23 +0000862 if (needsCast) {
863 DiagnosticsEngine &Diags = Ctx.getDiagnostics();
864 // FIXME: Use a custom category name to distinguish migration diagnostics.
865 unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
Argyrios Kyrtzidis927a4372012-06-20 01:28:32 +0000866 "converting to boxing syntax requires casting %0 to %1");
867 Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
868 << Msg->getSourceRange();
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000869 return false;
Argyrios Kyrtzidisb4822602012-05-24 16:48:23 +0000870 }
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000871
872 SourceRange ArgRange = OrigArg->getSourceRange();
Argyrios Kyrtzidis7bd957c2012-05-15 22:22:10 +0000873 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
Argyrios Kyrtzidis491e4ae2012-05-15 19:17:49 +0000874
875 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
876 commit.insertBefore(ArgRange.getBegin(), "@");
877 else
878 commit.insertWrap("@(", ArgRange, ")");
879
880 return true;
881}
Argyrios Kyrtzidis7bd957c2012-05-15 22:22:10 +0000882
883//===----------------------------------------------------------------------===//
884// rewriteToStringBoxedExpression.
885//===----------------------------------------------------------------------===//
886
887static bool doRewriteToUTF8StringBoxedExpressionHelper(
888 const ObjCMessageExpr *Msg,
889 const NSAPI &NS, Commit &commit) {
890 const Expr *Arg = Msg->getArg(0);
891 if (Arg->isTypeDependent())
892 return false;
893
Argyrios Kyrtzidis81541472012-05-16 00:21:21 +0000894 ASTContext &Ctx = NS.getASTContext();
895
Argyrios Kyrtzidis7bd957c2012-05-15 22:22:10 +0000896 const Expr *OrigArg = Arg->IgnoreImpCasts();
897 QualType OrigTy = OrigArg->getType();
Argyrios Kyrtzidis81541472012-05-16 00:21:21 +0000898 if (OrigTy->isArrayType())
899 OrigTy = Ctx.getArrayDecayedType(OrigTy);
Argyrios Kyrtzidis7bd957c2012-05-15 22:22:10 +0000900
901 if (const StringLiteral *
902 StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
903 commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
904 commit.insert(StrE->getLocStart(), "@");
905 return true;
906 }
907
Argyrios Kyrtzidis7bd957c2012-05-15 22:22:10 +0000908 if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
909 QualType PointeeType = PT->getPointeeType();
910 if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
911 SourceRange ArgRange = OrigArg->getSourceRange();
912 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
913
914 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
915 commit.insertBefore(ArgRange.getBegin(), "@");
916 else
917 commit.insertWrap("@(", ArgRange, ")");
918
919 return true;
920 }
921 }
922
923 return false;
924}
925
926static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
927 const NSAPI &NS, Commit &commit) {
928 Selector Sel = Msg->getSelector();
929
930 if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
931 Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) {
932 if (Msg->getNumArgs() != 1)
933 return false;
934 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
935 }
936
937 if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
938 if (Msg->getNumArgs() != 2)
939 return false;
940
941 const Expr *encodingArg = Msg->getArg(1);
942 if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
943 NS.isNSASCIIStringEncodingConstant(encodingArg))
944 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
945 }
946
947 return false;
948}