1f7639e1bSTed Kremenek //===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
2f7639e1bSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f7639e1bSTed Kremenek //
7f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
8f7639e1bSTed Kremenek //
9f7639e1bSTed Kremenek // Rewrites legacy method calls to modern syntax.
10f7639e1bSTed Kremenek //
11f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
12f7639e1bSTed Kremenek
13f7639e1bSTed Kremenek #include "clang/Edit/Rewriters.h"
143a02247dSChandler Carruth #include "clang/AST/ASTContext.h"
153a02247dSChandler Carruth #include "clang/AST/ExprCXX.h"
163a02247dSChandler Carruth #include "clang/AST/ExprObjC.h"
173a02247dSChandler Carruth #include "clang/AST/NSAPI.h"
186b4f341eSArgyrios Kyrtzidis #include "clang/AST/ParentMap.h"
19f7639e1bSTed Kremenek #include "clang/Edit/Commit.h"
20f7639e1bSTed Kremenek #include "clang/Lex/Lexer.h"
21f7639e1bSTed Kremenek
22f7639e1bSTed Kremenek using namespace clang;
23f7639e1bSTed Kremenek using namespace edit;
24f7639e1bSTed Kremenek
checkForLiteralCreation(const ObjCMessageExpr * Msg,IdentifierInfo * & ClassId,const LangOptions & LangOpts)25f7639e1bSTed Kremenek static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
2663aebfb4SArgyrios Kyrtzidis IdentifierInfo *&ClassId,
2763aebfb4SArgyrios Kyrtzidis const LangOptions &LangOpts) {
28f7639e1bSTed Kremenek if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
29f7639e1bSTed Kremenek return false;
30f7639e1bSTed Kremenek
31f7639e1bSTed Kremenek const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
32f7639e1bSTed Kremenek if (!Receiver)
33f7639e1bSTed Kremenek return false;
34f7639e1bSTed Kremenek ClassId = Receiver->getIdentifier();
35f7639e1bSTed Kremenek
36f7639e1bSTed Kremenek if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
37f7639e1bSTed Kremenek return true;
38f7639e1bSTed Kremenek
3963aebfb4SArgyrios Kyrtzidis // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
4063aebfb4SArgyrios Kyrtzidis // since the change from +1 to +0 will be handled fine by ARC.
4163aebfb4SArgyrios Kyrtzidis if (LangOpts.ObjCAutoRefCount) {
4263aebfb4SArgyrios Kyrtzidis if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
4363aebfb4SArgyrios Kyrtzidis if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
4463aebfb4SArgyrios Kyrtzidis Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
4563aebfb4SArgyrios Kyrtzidis if (Rec->getMethodFamily() == OMF_alloc)
4663aebfb4SArgyrios Kyrtzidis return true;
4763aebfb4SArgyrios Kyrtzidis }
4863aebfb4SArgyrios Kyrtzidis }
4963aebfb4SArgyrios Kyrtzidis }
5063aebfb4SArgyrios Kyrtzidis
51f7639e1bSTed Kremenek return false;
52f7639e1bSTed Kremenek }
53f7639e1bSTed Kremenek
54f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
55f7639e1bSTed Kremenek // rewriteObjCRedundantCallWithLiteral.
56f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
57f7639e1bSTed Kremenek
rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)58f7639e1bSTed Kremenek bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
59f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit) {
602145bc02SCraig Topper IdentifierInfo *II = nullptr;
6163aebfb4SArgyrios Kyrtzidis if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
62f7639e1bSTed Kremenek return false;
63f7639e1bSTed Kremenek if (Msg->getNumArgs() != 1)
64f7639e1bSTed Kremenek return false;
65f7639e1bSTed Kremenek
66f7639e1bSTed Kremenek const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
67f7639e1bSTed Kremenek Selector Sel = Msg->getSelector();
68f7639e1bSTed Kremenek
69f7639e1bSTed Kremenek if ((isa<ObjCStringLiteral>(Arg) &&
70f7639e1bSTed Kremenek NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
7163aebfb4SArgyrios Kyrtzidis (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
7263aebfb4SArgyrios Kyrtzidis NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel)) ||
73f7639e1bSTed Kremenek
74f7639e1bSTed Kremenek (isa<ObjCArrayLiteral>(Arg) &&
75f7639e1bSTed Kremenek NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
7663aebfb4SArgyrios Kyrtzidis (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
7763aebfb4SArgyrios Kyrtzidis NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel)) ||
78f7639e1bSTed Kremenek
79f7639e1bSTed Kremenek (isa<ObjCDictionaryLiteral>(Arg) &&
80f7639e1bSTed Kremenek NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
8163aebfb4SArgyrios Kyrtzidis (NS.getNSDictionarySelector(
8263aebfb4SArgyrios Kyrtzidis NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
8363aebfb4SArgyrios Kyrtzidis NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
84f7639e1bSTed Kremenek
85f7639e1bSTed Kremenek commit.replaceWithInner(Msg->getSourceRange(),
86f7639e1bSTed Kremenek Msg->getArg(0)->getSourceRange());
87f7639e1bSTed Kremenek return true;
88f7639e1bSTed Kremenek }
89f7639e1bSTed Kremenek
90f7639e1bSTed Kremenek return false;
91f7639e1bSTed Kremenek }
92f7639e1bSTed Kremenek
93f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
94f7639e1bSTed Kremenek // rewriteToObjCSubscriptSyntax.
95f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
96f7639e1bSTed Kremenek
979fc8faf9SAdrian Prantl /// Check for classes that accept 'objectForKey:' (or the other selectors
9889b928ebSArgyrios Kyrtzidis /// that the migrator handles) but return their instances as 'id', resulting
9989b928ebSArgyrios Kyrtzidis /// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
10089b928ebSArgyrios Kyrtzidis ///
10189b928ebSArgyrios Kyrtzidis /// When checking if we can convert to subscripting syntax, check whether
10289b928ebSArgyrios Kyrtzidis /// the receiver is a result of a class method from a hardcoded list of
10389b928ebSArgyrios Kyrtzidis /// such classes. In such a case return the specific class as the interface
10489b928ebSArgyrios Kyrtzidis /// of the receiver.
10589b928ebSArgyrios Kyrtzidis ///
10689b928ebSArgyrios Kyrtzidis /// FIXME: Remove this when these classes start using 'instancetype'.
10789b928ebSArgyrios Kyrtzidis static const ObjCInterfaceDecl *
maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl * IFace,const Expr * Receiver,ASTContext & Ctx)10889b928ebSArgyrios Kyrtzidis maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
10989b928ebSArgyrios Kyrtzidis const Expr *Receiver,
11089b928ebSArgyrios Kyrtzidis ASTContext &Ctx) {
11189b928ebSArgyrios Kyrtzidis assert(IFace && Receiver);
11289b928ebSArgyrios Kyrtzidis
11389b928ebSArgyrios Kyrtzidis // If the receiver has type 'id'...
11489b928ebSArgyrios Kyrtzidis if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
11589b928ebSArgyrios Kyrtzidis return IFace;
11689b928ebSArgyrios Kyrtzidis
11789b928ebSArgyrios Kyrtzidis const ObjCMessageExpr *
11889b928ebSArgyrios Kyrtzidis InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
11989b928ebSArgyrios Kyrtzidis if (!InnerMsg)
12089b928ebSArgyrios Kyrtzidis return IFace;
12189b928ebSArgyrios Kyrtzidis
12289b928ebSArgyrios Kyrtzidis QualType ClassRec;
12389b928ebSArgyrios Kyrtzidis switch (InnerMsg->getReceiverKind()) {
12489b928ebSArgyrios Kyrtzidis case ObjCMessageExpr::Instance:
12589b928ebSArgyrios Kyrtzidis case ObjCMessageExpr::SuperInstance:
12689b928ebSArgyrios Kyrtzidis return IFace;
12789b928ebSArgyrios Kyrtzidis
12889b928ebSArgyrios Kyrtzidis case ObjCMessageExpr::Class:
12989b928ebSArgyrios Kyrtzidis ClassRec = InnerMsg->getClassReceiver();
13089b928ebSArgyrios Kyrtzidis break;
13189b928ebSArgyrios Kyrtzidis case ObjCMessageExpr::SuperClass:
13289b928ebSArgyrios Kyrtzidis ClassRec = InnerMsg->getSuperType();
13389b928ebSArgyrios Kyrtzidis break;
13489b928ebSArgyrios Kyrtzidis }
13589b928ebSArgyrios Kyrtzidis
13689b928ebSArgyrios Kyrtzidis if (ClassRec.isNull())
13789b928ebSArgyrios Kyrtzidis return IFace;
13889b928ebSArgyrios Kyrtzidis
13989b928ebSArgyrios Kyrtzidis // ...and it is the result of a class message...
14089b928ebSArgyrios Kyrtzidis
14189b928ebSArgyrios Kyrtzidis const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
14289b928ebSArgyrios Kyrtzidis if (!ObjTy)
14389b928ebSArgyrios Kyrtzidis return IFace;
14489b928ebSArgyrios Kyrtzidis const ObjCInterfaceDecl *OID = ObjTy->getInterface();
14589b928ebSArgyrios Kyrtzidis
14689b928ebSArgyrios Kyrtzidis // ...and the receiving class is NSMapTable or NSLocale, return that
14789b928ebSArgyrios Kyrtzidis // class as the receiving interface.
14889b928ebSArgyrios Kyrtzidis if (OID->getName() == "NSMapTable" ||
14989b928ebSArgyrios Kyrtzidis OID->getName() == "NSLocale")
15089b928ebSArgyrios Kyrtzidis return OID;
15189b928ebSArgyrios Kyrtzidis
15289b928ebSArgyrios Kyrtzidis return IFace;
15389b928ebSArgyrios Kyrtzidis }
15489b928ebSArgyrios Kyrtzidis
canRewriteToSubscriptSyntax(const ObjCInterfaceDecl * & IFace,const ObjCMessageExpr * Msg,ASTContext & Ctx,Selector subscriptSel)15589b928ebSArgyrios Kyrtzidis static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
15689b928ebSArgyrios Kyrtzidis const ObjCMessageExpr *Msg,
15789b928ebSArgyrios Kyrtzidis ASTContext &Ctx,
15813b92929SArgyrios Kyrtzidis Selector subscriptSel) {
15989b928ebSArgyrios Kyrtzidis const Expr *Rec = Msg->getInstanceReceiver();
16089b928ebSArgyrios Kyrtzidis if (!Rec)
16189b928ebSArgyrios Kyrtzidis return false;
16289b928ebSArgyrios Kyrtzidis IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
16389b928ebSArgyrios Kyrtzidis
16413b92929SArgyrios Kyrtzidis if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
16513b92929SArgyrios Kyrtzidis if (!MD->isUnavailable())
16613b92929SArgyrios Kyrtzidis return true;
16713b92929SArgyrios Kyrtzidis }
16813b92929SArgyrios Kyrtzidis return false;
16913b92929SArgyrios Kyrtzidis }
17013b92929SArgyrios Kyrtzidis
1710bbe94f7SArgyrios Kyrtzidis static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
1720bbe94f7SArgyrios Kyrtzidis
maybePutParensOnReceiver(const Expr * Receiver,Commit & commit)173f7639e1bSTed Kremenek static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
1740bbe94f7SArgyrios Kyrtzidis if (subscriptOperatorNeedsParens(Receiver)) {
175f7639e1bSTed Kremenek SourceRange RecRange = Receiver->getSourceRange();
176f7639e1bSTed Kremenek commit.insertWrap("(", RecRange, ")");
177f7639e1bSTed Kremenek }
178f7639e1bSTed Kremenek }
179f7639e1bSTed Kremenek
rewriteToSubscriptGetCommon(const ObjCMessageExpr * Msg,Commit & commit)1806310fdd9SArgyrios Kyrtzidis static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
1816310fdd9SArgyrios Kyrtzidis Commit &commit) {
182f7639e1bSTed Kremenek if (Msg->getNumArgs() != 1)
183f7639e1bSTed Kremenek return false;
184f7639e1bSTed Kremenek const Expr *Rec = Msg->getInstanceReceiver();
185f7639e1bSTed Kremenek if (!Rec)
186f7639e1bSTed Kremenek return false;
187f7639e1bSTed Kremenek
188f7639e1bSTed Kremenek SourceRange MsgRange = Msg->getSourceRange();
189f7639e1bSTed Kremenek SourceRange RecRange = Rec->getSourceRange();
190f7639e1bSTed Kremenek SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
191f7639e1bSTed Kremenek
192f7639e1bSTed Kremenek commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
193f7639e1bSTed Kremenek ArgRange.getBegin()),
194f7639e1bSTed Kremenek CharSourceRange::getTokenRange(RecRange));
195f7639e1bSTed Kremenek commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
196f7639e1bSTed Kremenek ArgRange);
197f7639e1bSTed Kremenek commit.insertWrap("[", ArgRange, "]");
198f7639e1bSTed Kremenek maybePutParensOnReceiver(Rec, commit);
199f7639e1bSTed Kremenek return true;
200f7639e1bSTed Kremenek }
201f7639e1bSTed Kremenek
rewriteToArraySubscriptGet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2026310fdd9SArgyrios Kyrtzidis static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
2036310fdd9SArgyrios Kyrtzidis const ObjCMessageExpr *Msg,
2046310fdd9SArgyrios Kyrtzidis const NSAPI &NS,
2056310fdd9SArgyrios Kyrtzidis Commit &commit) {
20689b928ebSArgyrios Kyrtzidis if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
20713b92929SArgyrios Kyrtzidis NS.getObjectAtIndexedSubscriptSelector()))
2086310fdd9SArgyrios Kyrtzidis return false;
2096310fdd9SArgyrios Kyrtzidis return rewriteToSubscriptGetCommon(Msg, commit);
2106310fdd9SArgyrios Kyrtzidis }
2116310fdd9SArgyrios Kyrtzidis
rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2126310fdd9SArgyrios Kyrtzidis static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
2136310fdd9SArgyrios Kyrtzidis const ObjCMessageExpr *Msg,
2146310fdd9SArgyrios Kyrtzidis const NSAPI &NS,
2156310fdd9SArgyrios Kyrtzidis Commit &commit) {
21689b928ebSArgyrios Kyrtzidis if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
21713b92929SArgyrios Kyrtzidis NS.getObjectForKeyedSubscriptSelector()))
2186310fdd9SArgyrios Kyrtzidis return false;
2196310fdd9SArgyrios Kyrtzidis return rewriteToSubscriptGetCommon(Msg, commit);
2206310fdd9SArgyrios Kyrtzidis }
2216310fdd9SArgyrios Kyrtzidis
rewriteToArraySubscriptSet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2226310fdd9SArgyrios Kyrtzidis static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
2236310fdd9SArgyrios Kyrtzidis const ObjCMessageExpr *Msg,
2246310fdd9SArgyrios Kyrtzidis const NSAPI &NS,
225f7639e1bSTed Kremenek Commit &commit) {
22689b928ebSArgyrios Kyrtzidis if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
22713b92929SArgyrios Kyrtzidis NS.getSetObjectAtIndexedSubscriptSelector()))
22813b92929SArgyrios Kyrtzidis return false;
22913b92929SArgyrios Kyrtzidis
230f7639e1bSTed Kremenek if (Msg->getNumArgs() != 2)
231f7639e1bSTed Kremenek return false;
232f7639e1bSTed Kremenek const Expr *Rec = Msg->getInstanceReceiver();
233f7639e1bSTed Kremenek if (!Rec)
234f7639e1bSTed Kremenek return false;
235f7639e1bSTed Kremenek
236f7639e1bSTed Kremenek SourceRange MsgRange = Msg->getSourceRange();
237f7639e1bSTed Kremenek SourceRange RecRange = Rec->getSourceRange();
238f7639e1bSTed Kremenek SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
239f7639e1bSTed Kremenek SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
240f7639e1bSTed Kremenek
241f7639e1bSTed Kremenek commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
242f7639e1bSTed Kremenek Arg0Range.getBegin()),
243f7639e1bSTed Kremenek CharSourceRange::getTokenRange(RecRange));
244f7639e1bSTed Kremenek commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
245f7639e1bSTed Kremenek Arg1Range.getBegin()),
246f7639e1bSTed Kremenek CharSourceRange::getTokenRange(Arg0Range));
247f7639e1bSTed Kremenek commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
248f7639e1bSTed Kremenek Arg1Range);
249f7639e1bSTed Kremenek commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
250f7639e1bSTed Kremenek Arg1Range.getBegin()),
251f7639e1bSTed Kremenek "] = ");
252f7639e1bSTed Kremenek maybePutParensOnReceiver(Rec, commit);
253f7639e1bSTed Kremenek return true;
254f7639e1bSTed Kremenek }
255f7639e1bSTed Kremenek
rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2566310fdd9SArgyrios Kyrtzidis static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
2576310fdd9SArgyrios Kyrtzidis const ObjCMessageExpr *Msg,
2586310fdd9SArgyrios Kyrtzidis const NSAPI &NS,
259f7639e1bSTed Kremenek Commit &commit) {
26089b928ebSArgyrios Kyrtzidis if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
26113b92929SArgyrios Kyrtzidis NS.getSetObjectForKeyedSubscriptSelector()))
26213b92929SArgyrios Kyrtzidis return false;
26313b92929SArgyrios Kyrtzidis
264f7639e1bSTed Kremenek if (Msg->getNumArgs() != 2)
265f7639e1bSTed Kremenek return false;
266f7639e1bSTed Kremenek const Expr *Rec = Msg->getInstanceReceiver();
267f7639e1bSTed Kremenek if (!Rec)
268f7639e1bSTed Kremenek return false;
269f7639e1bSTed Kremenek
270f7639e1bSTed Kremenek SourceRange MsgRange = Msg->getSourceRange();
271f7639e1bSTed Kremenek SourceRange RecRange = Rec->getSourceRange();
272f7639e1bSTed Kremenek SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
273f7639e1bSTed Kremenek SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
274f7639e1bSTed Kremenek
275f7639e1bSTed Kremenek SourceLocation LocBeforeVal = Arg0Range.getBegin();
276f7639e1bSTed Kremenek commit.insertBefore(LocBeforeVal, "] = ");
277f7639e1bSTed Kremenek commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
278f7639e1bSTed Kremenek /*beforePreviousInsertions=*/true);
279f7639e1bSTed Kremenek commit.insertBefore(LocBeforeVal, "[");
280f7639e1bSTed Kremenek commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
281f7639e1bSTed Kremenek Arg0Range.getBegin()),
282f7639e1bSTed Kremenek CharSourceRange::getTokenRange(RecRange));
283f7639e1bSTed Kremenek commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
284f7639e1bSTed Kremenek Arg0Range);
285f7639e1bSTed Kremenek maybePutParensOnReceiver(Rec, commit);
286f7639e1bSTed Kremenek return true;
287f7639e1bSTed Kremenek }
288f7639e1bSTed Kremenek
rewriteToObjCSubscriptSyntax(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)289f7639e1bSTed Kremenek bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
290f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit) {
291f7639e1bSTed Kremenek if (!Msg || Msg->isImplicit() ||
292f7639e1bSTed Kremenek Msg->getReceiverKind() != ObjCMessageExpr::Instance)
293f7639e1bSTed Kremenek return false;
294f7639e1bSTed Kremenek const ObjCMethodDecl *Method = Msg->getMethodDecl();
295f7639e1bSTed Kremenek if (!Method)
296f7639e1bSTed Kremenek return false;
297f7639e1bSTed Kremenek
29860e92e55SDmitri Gribenko const ObjCInterfaceDecl *IFace =
29960e92e55SDmitri Gribenko NS.getASTContext().getObjContainingInterface(Method);
300f7639e1bSTed Kremenek if (!IFace)
301f7639e1bSTed Kremenek return false;
302f7639e1bSTed Kremenek Selector Sel = Msg->getSelector();
303f7639e1bSTed Kremenek
30413b92929SArgyrios Kyrtzidis if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
3056310fdd9SArgyrios Kyrtzidis return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
3066310fdd9SArgyrios Kyrtzidis
30713b92929SArgyrios Kyrtzidis if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
3086310fdd9SArgyrios Kyrtzidis return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
309f7639e1bSTed Kremenek
310f7639e1bSTed Kremenek if (Msg->getNumArgs() != 2)
311f7639e1bSTed Kremenek return false;
312f7639e1bSTed Kremenek
31313b92929SArgyrios Kyrtzidis if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
3146310fdd9SArgyrios Kyrtzidis return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
315f7639e1bSTed Kremenek
31613b92929SArgyrios Kyrtzidis if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
3176310fdd9SArgyrios Kyrtzidis return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
318f7639e1bSTed Kremenek
319f7639e1bSTed Kremenek return false;
320f7639e1bSTed Kremenek }
321f7639e1bSTed Kremenek
322f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
323f7639e1bSTed Kremenek // rewriteToObjCLiteralSyntax.
324f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
325f7639e1bSTed Kremenek
326f7639e1bSTed Kremenek static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
3276b4f341eSArgyrios Kyrtzidis const NSAPI &NS, Commit &commit,
3286b4f341eSArgyrios Kyrtzidis const ParentMap *PMap);
329f7639e1bSTed Kremenek static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
330f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit);
331f7639e1bSTed Kremenek static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
332f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit);
333491e4aedSArgyrios Kyrtzidis static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
334491e4aedSArgyrios Kyrtzidis const NSAPI &NS, Commit &commit);
3357bd957c1SArgyrios Kyrtzidis static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
3367bd957c1SArgyrios Kyrtzidis const NSAPI &NS, Commit &commit);
337f7639e1bSTed Kremenek
rewriteToObjCLiteralSyntax(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit,const ParentMap * PMap)338f7639e1bSTed Kremenek bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
3396b4f341eSArgyrios Kyrtzidis const NSAPI &NS, Commit &commit,
3406b4f341eSArgyrios Kyrtzidis const ParentMap *PMap) {
3412145bc02SCraig Topper IdentifierInfo *II = nullptr;
34263aebfb4SArgyrios Kyrtzidis if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
343f7639e1bSTed Kremenek return false;
344f7639e1bSTed Kremenek
345f7639e1bSTed Kremenek if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
3466b4f341eSArgyrios Kyrtzidis return rewriteToArrayLiteral(Msg, NS, commit, PMap);
347f7639e1bSTed Kremenek if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
348f7639e1bSTed Kremenek return rewriteToDictionaryLiteral(Msg, NS, commit);
349f7639e1bSTed Kremenek if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
350f7639e1bSTed Kremenek return rewriteToNumberLiteral(Msg, NS, commit);
3517bd957c1SArgyrios Kyrtzidis if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
3527bd957c1SArgyrios Kyrtzidis return rewriteToStringBoxedExpression(Msg, NS, commit);
353f7639e1bSTed Kremenek
354f7639e1bSTed Kremenek return false;
355f7639e1bSTed Kremenek }
356f7639e1bSTed Kremenek
3579fc8faf9SAdrian Prantl /// Returns true if the immediate message arguments of \c Msg should not
3586b4f341eSArgyrios Kyrtzidis /// be rewritten because it will interfere with the rewrite of the parent
3596b4f341eSArgyrios Kyrtzidis /// message expression. e.g.
3606b4f341eSArgyrios Kyrtzidis /// \code
3616b4f341eSArgyrios Kyrtzidis /// [NSDictionary dictionaryWithObjects:
3626b4f341eSArgyrios Kyrtzidis /// [NSArray arrayWithObjects:@"1", @"2", nil]
3636b4f341eSArgyrios Kyrtzidis /// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
3646b4f341eSArgyrios Kyrtzidis /// \endcode
3656b4f341eSArgyrios Kyrtzidis /// It will return true for this because we are going to rewrite this directly
3666b4f341eSArgyrios Kyrtzidis /// to a dictionary literal without any array literals.
3676b4f341eSArgyrios Kyrtzidis static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
3686b4f341eSArgyrios Kyrtzidis const NSAPI &NS);
3696b4f341eSArgyrios Kyrtzidis
370f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
371f7639e1bSTed Kremenek // rewriteToArrayLiteral.
372f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
373f7639e1bSTed Kremenek
3749fc8faf9SAdrian Prantl /// Adds an explicit cast to 'id' if the type is not objc object.
375c1dfed65SArgyrios Kyrtzidis static void objectifyExpr(const Expr *E, Commit &commit);
376c1dfed65SArgyrios Kyrtzidis
rewriteToArrayLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit,const ParentMap * PMap)377f7639e1bSTed Kremenek static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
3786b4f341eSArgyrios Kyrtzidis const NSAPI &NS, Commit &commit,
3796b4f341eSArgyrios Kyrtzidis const ParentMap *PMap) {
3806b4f341eSArgyrios Kyrtzidis if (PMap) {
3816b4f341eSArgyrios Kyrtzidis const ObjCMessageExpr *ParentMsg =
3826b4f341eSArgyrios Kyrtzidis dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
3836b4f341eSArgyrios Kyrtzidis if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
3846b4f341eSArgyrios Kyrtzidis return false;
3856b4f341eSArgyrios Kyrtzidis }
3866b4f341eSArgyrios Kyrtzidis
387f7639e1bSTed Kremenek Selector Sel = Msg->getSelector();
388f7639e1bSTed Kremenek SourceRange MsgRange = Msg->getSourceRange();
389f7639e1bSTed Kremenek
390f7639e1bSTed Kremenek if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
391f7639e1bSTed Kremenek if (Msg->getNumArgs() != 0)
392f7639e1bSTed Kremenek return false;
393f7639e1bSTed Kremenek commit.replace(MsgRange, "@[]");
394f7639e1bSTed Kremenek return true;
395f7639e1bSTed Kremenek }
396f7639e1bSTed Kremenek
397f7639e1bSTed Kremenek if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
398f7639e1bSTed Kremenek if (Msg->getNumArgs() != 1)
399f7639e1bSTed Kremenek return false;
400c1dfed65SArgyrios Kyrtzidis objectifyExpr(Msg->getArg(0), commit);
401f7639e1bSTed Kremenek SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
402f7639e1bSTed Kremenek commit.replaceWithInner(MsgRange, ArgRange);
403f7639e1bSTed Kremenek commit.insertWrap("@[", ArgRange, "]");
404f7639e1bSTed Kremenek return true;
405f7639e1bSTed Kremenek }
406f7639e1bSTed Kremenek
40763aebfb4SArgyrios Kyrtzidis if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
40863aebfb4SArgyrios Kyrtzidis Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
409f7639e1bSTed Kremenek if (Msg->getNumArgs() == 0)
410f7639e1bSTed Kremenek return false;
411f7639e1bSTed Kremenek const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
412f7639e1bSTed Kremenek if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
413f7639e1bSTed Kremenek return false;
414f7639e1bSTed Kremenek
415c1dfed65SArgyrios Kyrtzidis for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
416c1dfed65SArgyrios Kyrtzidis objectifyExpr(Msg->getArg(i), commit);
417c1dfed65SArgyrios Kyrtzidis
418f7639e1bSTed Kremenek if (Msg->getNumArgs() == 1) {
419f7639e1bSTed Kremenek commit.replace(MsgRange, "@[]");
420f7639e1bSTed Kremenek return true;
421f7639e1bSTed Kremenek }
422f2ceec48SStephen Kelly SourceRange ArgRange(Msg->getArg(0)->getBeginLoc(),
4231c301dcbSStephen Kelly Msg->getArg(Msg->getNumArgs() - 2)->getEndLoc());
424f7639e1bSTed Kremenek commit.replaceWithInner(MsgRange, ArgRange);
425f7639e1bSTed Kremenek commit.insertWrap("@[", ArgRange, "]");
426f7639e1bSTed Kremenek return true;
427f7639e1bSTed Kremenek }
428f7639e1bSTed Kremenek
429f7639e1bSTed Kremenek return false;
430f7639e1bSTed Kremenek }
431f7639e1bSTed Kremenek
432f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
433f7639e1bSTed Kremenek // rewriteToDictionaryLiteral.
434f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
435f7639e1bSTed Kremenek
4369fc8faf9SAdrian Prantl /// If \c Msg is an NSArray creation message or literal, this gets the
4376b4f341eSArgyrios Kyrtzidis /// objects that were used to create it.
4386b4f341eSArgyrios Kyrtzidis /// \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)4396b4f341eSArgyrios Kyrtzidis static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
4406b4f341eSArgyrios Kyrtzidis SmallVectorImpl<const Expr *> &Objs) {
4416b4f341eSArgyrios Kyrtzidis if (!E)
4426b4f341eSArgyrios Kyrtzidis return false;
4436b4f341eSArgyrios Kyrtzidis
4446b4f341eSArgyrios Kyrtzidis E = E->IgnoreParenCasts();
4456b4f341eSArgyrios Kyrtzidis if (!E)
4466b4f341eSArgyrios Kyrtzidis return false;
4476b4f341eSArgyrios Kyrtzidis
4486b4f341eSArgyrios Kyrtzidis if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
4492145bc02SCraig Topper IdentifierInfo *Cls = nullptr;
4506b4f341eSArgyrios Kyrtzidis if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
4516b4f341eSArgyrios Kyrtzidis return false;
4526b4f341eSArgyrios Kyrtzidis
4536b4f341eSArgyrios Kyrtzidis if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
4546b4f341eSArgyrios Kyrtzidis return false;
4556b4f341eSArgyrios Kyrtzidis
4566b4f341eSArgyrios Kyrtzidis Selector Sel = Msg->getSelector();
4576b4f341eSArgyrios Kyrtzidis if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
4586b4f341eSArgyrios Kyrtzidis return true; // empty array.
4596b4f341eSArgyrios Kyrtzidis
4606b4f341eSArgyrios Kyrtzidis if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
4616b4f341eSArgyrios Kyrtzidis if (Msg->getNumArgs() != 1)
4626b4f341eSArgyrios Kyrtzidis return false;
4636b4f341eSArgyrios Kyrtzidis Objs.push_back(Msg->getArg(0));
4646b4f341eSArgyrios Kyrtzidis return true;
4656b4f341eSArgyrios Kyrtzidis }
4666b4f341eSArgyrios Kyrtzidis
4676b4f341eSArgyrios Kyrtzidis if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
4686b4f341eSArgyrios Kyrtzidis Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
4696b4f341eSArgyrios Kyrtzidis if (Msg->getNumArgs() == 0)
4706b4f341eSArgyrios Kyrtzidis return false;
4716b4f341eSArgyrios Kyrtzidis const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
4726b4f341eSArgyrios Kyrtzidis if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
4736b4f341eSArgyrios Kyrtzidis return false;
4746b4f341eSArgyrios Kyrtzidis
4756b4f341eSArgyrios Kyrtzidis for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
4766b4f341eSArgyrios Kyrtzidis Objs.push_back(Msg->getArg(i));
4776b4f341eSArgyrios Kyrtzidis return true;
4786b4f341eSArgyrios Kyrtzidis }
4796b4f341eSArgyrios Kyrtzidis
4806b4f341eSArgyrios Kyrtzidis } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
4816b4f341eSArgyrios Kyrtzidis for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
4826b4f341eSArgyrios Kyrtzidis Objs.push_back(ArrLit->getElement(i));
4836b4f341eSArgyrios Kyrtzidis return true;
4846b4f341eSArgyrios Kyrtzidis }
4856b4f341eSArgyrios Kyrtzidis
4866b4f341eSArgyrios Kyrtzidis return false;
4876b4f341eSArgyrios Kyrtzidis }
4886b4f341eSArgyrios Kyrtzidis
rewriteToDictionaryLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)489f7639e1bSTed Kremenek static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
490f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit) {
491f7639e1bSTed Kremenek Selector Sel = Msg->getSelector();
492f7639e1bSTed Kremenek SourceRange MsgRange = Msg->getSourceRange();
493f7639e1bSTed Kremenek
494f7639e1bSTed Kremenek if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
495f7639e1bSTed Kremenek if (Msg->getNumArgs() != 0)
496f7639e1bSTed Kremenek return false;
497f7639e1bSTed Kremenek commit.replace(MsgRange, "@{}");
498f7639e1bSTed Kremenek return true;
499f7639e1bSTed Kremenek }
500f7639e1bSTed Kremenek
501f7639e1bSTed Kremenek if (Sel == NS.getNSDictionarySelector(
502f7639e1bSTed Kremenek NSAPI::NSDict_dictionaryWithObjectForKey)) {
503f7639e1bSTed Kremenek if (Msg->getNumArgs() != 2)
504f7639e1bSTed Kremenek return false;
505c1dfed65SArgyrios Kyrtzidis
506c1dfed65SArgyrios Kyrtzidis objectifyExpr(Msg->getArg(0), commit);
507c1dfed65SArgyrios Kyrtzidis objectifyExpr(Msg->getArg(1), commit);
508c1dfed65SArgyrios Kyrtzidis
509f7639e1bSTed Kremenek SourceRange ValRange = Msg->getArg(0)->getSourceRange();
510f7639e1bSTed Kremenek SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
511f7639e1bSTed Kremenek // Insert key before the value.
512f7639e1bSTed Kremenek commit.insertBefore(ValRange.getBegin(), ": ");
513f7639e1bSTed Kremenek commit.insertFromRange(ValRange.getBegin(),
514f7639e1bSTed Kremenek CharSourceRange::getTokenRange(KeyRange),
515f7639e1bSTed Kremenek /*afterToken=*/false, /*beforePreviousInsertions=*/true);
516f7639e1bSTed Kremenek commit.insertBefore(ValRange.getBegin(), "@{");
517f7639e1bSTed Kremenek commit.insertAfterToken(ValRange.getEnd(), "}");
518f7639e1bSTed Kremenek commit.replaceWithInner(MsgRange, ValRange);
519f7639e1bSTed Kremenek return true;
520f7639e1bSTed Kremenek }
521f7639e1bSTed Kremenek
522f7639e1bSTed Kremenek if (Sel == NS.getNSDictionarySelector(
52363aebfb4SArgyrios Kyrtzidis NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
52463aebfb4SArgyrios Kyrtzidis Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
525f7639e1bSTed Kremenek if (Msg->getNumArgs() % 2 != 1)
526f7639e1bSTed Kremenek return false;
527f7639e1bSTed Kremenek unsigned SentinelIdx = Msg->getNumArgs() - 1;
528f7639e1bSTed Kremenek const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
529f7639e1bSTed Kremenek if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
530f7639e1bSTed Kremenek return false;
531f7639e1bSTed Kremenek
532f7639e1bSTed Kremenek if (Msg->getNumArgs() == 1) {
533f7639e1bSTed Kremenek commit.replace(MsgRange, "@{}");
534f7639e1bSTed Kremenek return true;
535f7639e1bSTed Kremenek }
536f7639e1bSTed Kremenek
537f7639e1bSTed Kremenek for (unsigned i = 0; i < SentinelIdx; i += 2) {
538c1dfed65SArgyrios Kyrtzidis objectifyExpr(Msg->getArg(i), commit);
539c1dfed65SArgyrios Kyrtzidis objectifyExpr(Msg->getArg(i+1), commit);
540c1dfed65SArgyrios Kyrtzidis
541f7639e1bSTed Kremenek SourceRange ValRange = Msg->getArg(i)->getSourceRange();
542f7639e1bSTed Kremenek SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
543f7639e1bSTed Kremenek // Insert value after key.
544f7639e1bSTed Kremenek commit.insertAfterToken(KeyRange.getEnd(), ": ");
545f7639e1bSTed Kremenek commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
546f7639e1bSTed Kremenek commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
547f7639e1bSTed Kremenek KeyRange.getBegin()));
548f7639e1bSTed Kremenek }
549f7639e1bSTed Kremenek // Range of arguments up until and including the last key.
550f7639e1bSTed Kremenek // The sentinel and first value are cut off, the value will move after the
551f7639e1bSTed Kremenek // key.
552f2ceec48SStephen Kelly SourceRange ArgRange(Msg->getArg(1)->getBeginLoc(),
5531c301dcbSStephen Kelly Msg->getArg(SentinelIdx - 1)->getEndLoc());
554f7639e1bSTed Kremenek commit.insertWrap("@{", ArgRange, "}");
555f7639e1bSTed Kremenek commit.replaceWithInner(MsgRange, ArgRange);
556f7639e1bSTed Kremenek return true;
557f7639e1bSTed Kremenek }
558f7639e1bSTed Kremenek
5596b4f341eSArgyrios Kyrtzidis if (Sel == NS.getNSDictionarySelector(
5606b4f341eSArgyrios Kyrtzidis NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
5616b4f341eSArgyrios Kyrtzidis Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
5626b4f341eSArgyrios Kyrtzidis if (Msg->getNumArgs() != 2)
5636b4f341eSArgyrios Kyrtzidis return false;
5646b4f341eSArgyrios Kyrtzidis
5656b4f341eSArgyrios Kyrtzidis SmallVector<const Expr *, 8> Vals;
5666b4f341eSArgyrios Kyrtzidis if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
5676b4f341eSArgyrios Kyrtzidis return false;
5686b4f341eSArgyrios Kyrtzidis
5696b4f341eSArgyrios Kyrtzidis SmallVector<const Expr *, 8> Keys;
5706b4f341eSArgyrios Kyrtzidis if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
5716b4f341eSArgyrios Kyrtzidis return false;
5726b4f341eSArgyrios Kyrtzidis
5736b4f341eSArgyrios Kyrtzidis if (Vals.size() != Keys.size())
5746b4f341eSArgyrios Kyrtzidis return false;
5756b4f341eSArgyrios Kyrtzidis
5766b4f341eSArgyrios Kyrtzidis if (Vals.empty()) {
5776b4f341eSArgyrios Kyrtzidis commit.replace(MsgRange, "@{}");
5786b4f341eSArgyrios Kyrtzidis return true;
5796b4f341eSArgyrios Kyrtzidis }
5806b4f341eSArgyrios Kyrtzidis
5816b4f341eSArgyrios Kyrtzidis for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
5826b4f341eSArgyrios Kyrtzidis objectifyExpr(Vals[i], commit);
5836b4f341eSArgyrios Kyrtzidis objectifyExpr(Keys[i], commit);
5846b4f341eSArgyrios Kyrtzidis
5856b4f341eSArgyrios Kyrtzidis SourceRange ValRange = Vals[i]->getSourceRange();
5866b4f341eSArgyrios Kyrtzidis SourceRange KeyRange = Keys[i]->getSourceRange();
5876b4f341eSArgyrios Kyrtzidis // Insert value after key.
5886b4f341eSArgyrios Kyrtzidis commit.insertAfterToken(KeyRange.getEnd(), ": ");
5896b4f341eSArgyrios Kyrtzidis commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
5906b4f341eSArgyrios Kyrtzidis }
5916b4f341eSArgyrios Kyrtzidis // Range of arguments up until and including the last key.
5926b4f341eSArgyrios Kyrtzidis // The first value is cut off, the value will move after the key.
5931c301dcbSStephen Kelly SourceRange ArgRange(Keys.front()->getBeginLoc(), Keys.back()->getEndLoc());
5946b4f341eSArgyrios Kyrtzidis commit.insertWrap("@{", ArgRange, "}");
5956b4f341eSArgyrios Kyrtzidis commit.replaceWithInner(MsgRange, ArgRange);
5966b4f341eSArgyrios Kyrtzidis return true;
5976b4f341eSArgyrios Kyrtzidis }
5986b4f341eSArgyrios Kyrtzidis
5996b4f341eSArgyrios Kyrtzidis return false;
6006b4f341eSArgyrios Kyrtzidis }
6016b4f341eSArgyrios Kyrtzidis
shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr * Msg,const NSAPI & NS)6026b4f341eSArgyrios Kyrtzidis static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
6036b4f341eSArgyrios Kyrtzidis const NSAPI &NS) {
6046b4f341eSArgyrios Kyrtzidis if (!Msg)
6056b4f341eSArgyrios Kyrtzidis return false;
6066b4f341eSArgyrios Kyrtzidis
6072145bc02SCraig Topper IdentifierInfo *II = nullptr;
6086b4f341eSArgyrios Kyrtzidis if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
6096b4f341eSArgyrios Kyrtzidis return false;
6106b4f341eSArgyrios Kyrtzidis
6116b4f341eSArgyrios Kyrtzidis if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
6126b4f341eSArgyrios Kyrtzidis return false;
6136b4f341eSArgyrios Kyrtzidis
6146b4f341eSArgyrios Kyrtzidis Selector Sel = Msg->getSelector();
6156b4f341eSArgyrios Kyrtzidis if (Sel == NS.getNSDictionarySelector(
6166b4f341eSArgyrios Kyrtzidis NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
6176b4f341eSArgyrios Kyrtzidis Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
6186b4f341eSArgyrios Kyrtzidis if (Msg->getNumArgs() != 2)
6196b4f341eSArgyrios Kyrtzidis return false;
6206b4f341eSArgyrios Kyrtzidis
6216b4f341eSArgyrios Kyrtzidis SmallVector<const Expr *, 8> Vals;
6226b4f341eSArgyrios Kyrtzidis if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
6236b4f341eSArgyrios Kyrtzidis return false;
6246b4f341eSArgyrios Kyrtzidis
6256b4f341eSArgyrios Kyrtzidis SmallVector<const Expr *, 8> Keys;
6266b4f341eSArgyrios Kyrtzidis if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
6276b4f341eSArgyrios Kyrtzidis return false;
6286b4f341eSArgyrios Kyrtzidis
6296b4f341eSArgyrios Kyrtzidis if (Vals.size() != Keys.size())
6306b4f341eSArgyrios Kyrtzidis return false;
6316b4f341eSArgyrios Kyrtzidis
6326b4f341eSArgyrios Kyrtzidis return true;
6336b4f341eSArgyrios Kyrtzidis }
6346b4f341eSArgyrios Kyrtzidis
635f7639e1bSTed Kremenek return false;
636f7639e1bSTed Kremenek }
637f7639e1bSTed Kremenek
638f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
639f7639e1bSTed Kremenek // rewriteToNumberLiteral.
640f7639e1bSTed Kremenek //===----------------------------------------------------------------------===//
641f7639e1bSTed Kremenek
rewriteToCharLiteral(const ObjCMessageExpr * Msg,const CharacterLiteral * Arg,const NSAPI & NS,Commit & commit)642f7639e1bSTed Kremenek static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
643f7639e1bSTed Kremenek const CharacterLiteral *Arg,
644f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit) {
645f7639e1bSTed Kremenek if (Arg->getKind() != CharacterLiteral::Ascii)
646f7639e1bSTed Kremenek return false;
647f7639e1bSTed Kremenek if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
648f7639e1bSTed Kremenek Msg->getSelector())) {
649f7639e1bSTed Kremenek SourceRange ArgRange = Arg->getSourceRange();
650f7639e1bSTed Kremenek commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
651f7639e1bSTed Kremenek commit.insert(ArgRange.getBegin(), "@");
652f7639e1bSTed Kremenek return true;
653f7639e1bSTed Kremenek }
654f7639e1bSTed Kremenek
655491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
656f7639e1bSTed Kremenek }
657f7639e1bSTed Kremenek
rewriteToBoolLiteral(const ObjCMessageExpr * Msg,const Expr * Arg,const NSAPI & NS,Commit & commit)658f7639e1bSTed Kremenek static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
659f7639e1bSTed Kremenek const Expr *Arg,
660f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit) {
661f7639e1bSTed Kremenek if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
662f7639e1bSTed Kremenek Msg->getSelector())) {
663f7639e1bSTed Kremenek SourceRange ArgRange = Arg->getSourceRange();
664f7639e1bSTed Kremenek commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
665f7639e1bSTed Kremenek commit.insert(ArgRange.getBegin(), "@");
666f7639e1bSTed Kremenek return true;
667f7639e1bSTed Kremenek }
668f7639e1bSTed Kremenek
669491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
670f7639e1bSTed Kremenek }
671f7639e1bSTed Kremenek
672f7639e1bSTed Kremenek namespace {
673f7639e1bSTed Kremenek
674f7639e1bSTed Kremenek struct LiteralInfo {
675f7639e1bSTed Kremenek bool Hex, Octal;
676f7639e1bSTed Kremenek StringRef U, F, L, LL;
677f7639e1bSTed Kremenek CharSourceRange WithoutSuffRange;
678f7639e1bSTed Kremenek };
679f7639e1bSTed Kremenek
680f7639e1bSTed Kremenek }
681f7639e1bSTed Kremenek
getLiteralInfo(SourceRange literalRange,bool isFloat,bool isIntZero,ASTContext & Ctx,LiteralInfo & Info)682f7639e1bSTed Kremenek static bool getLiteralInfo(SourceRange literalRange,
683f7639e1bSTed Kremenek bool isFloat, bool isIntZero,
684f7639e1bSTed Kremenek ASTContext &Ctx, LiteralInfo &Info) {
685f7639e1bSTed Kremenek if (literalRange.getBegin().isMacroID() ||
686f7639e1bSTed Kremenek literalRange.getEnd().isMacroID())
687f7639e1bSTed Kremenek return false;
688f7639e1bSTed Kremenek StringRef text = Lexer::getSourceText(
689f7639e1bSTed Kremenek CharSourceRange::getTokenRange(literalRange),
690bbafb8a7SDavid Blaikie Ctx.getSourceManager(), Ctx.getLangOpts());
691f7639e1bSTed Kremenek if (text.empty())
692f7639e1bSTed Kremenek return false;
693f7639e1bSTed Kremenek
69405785d16SDavid Blaikie Optional<bool> UpperU, UpperL;
695f7639e1bSTed Kremenek bool UpperF = false;
696f7639e1bSTed Kremenek
697f7639e1bSTed Kremenek struct Suff {
698f7639e1bSTed Kremenek static bool has(StringRef suff, StringRef &text) {
699f7639e1bSTed Kremenek if (text.endswith(suff)) {
700f7639e1bSTed Kremenek text = text.substr(0, text.size()-suff.size());
701f7639e1bSTed Kremenek return true;
702f7639e1bSTed Kremenek }
703f7639e1bSTed Kremenek return false;
704f7639e1bSTed Kremenek }
705f7639e1bSTed Kremenek };
706f7639e1bSTed Kremenek
70740446663SKazu Hirata while (true) {
708f7639e1bSTed Kremenek if (Suff::has("u", text)) {
709f7639e1bSTed Kremenek UpperU = false;
710f7639e1bSTed Kremenek } else if (Suff::has("U", text)) {
711f7639e1bSTed Kremenek UpperU = true;
712f7639e1bSTed Kremenek } else if (Suff::has("ll", text)) {
713f7639e1bSTed Kremenek UpperL = false;
714f7639e1bSTed Kremenek } else if (Suff::has("LL", text)) {
715f7639e1bSTed Kremenek UpperL = true;
716f7639e1bSTed Kremenek } else if (Suff::has("l", text)) {
717f7639e1bSTed Kremenek UpperL = false;
718f7639e1bSTed Kremenek } else if (Suff::has("L", text)) {
719f7639e1bSTed Kremenek UpperL = true;
720f7639e1bSTed Kremenek } else if (isFloat && Suff::has("f", text)) {
721f7639e1bSTed Kremenek UpperF = false;
722f7639e1bSTed Kremenek } else if (isFloat && Suff::has("F", text)) {
723f7639e1bSTed Kremenek UpperF = true;
724f7639e1bSTed Kremenek } else
725f7639e1bSTed Kremenek break;
726f7639e1bSTed Kremenek }
727f7639e1bSTed Kremenek
728*97afce08SKazu Hirata if (!UpperU && !UpperL)
729f7639e1bSTed Kremenek UpperU = UpperL = true;
730*97afce08SKazu Hirata else if (UpperU && !UpperL)
731f7639e1bSTed Kremenek UpperL = UpperU;
732*97afce08SKazu Hirata else if (UpperL && !UpperU)
733f7639e1bSTed Kremenek UpperU = UpperL;
734f7639e1bSTed Kremenek
735f7639e1bSTed Kremenek Info.U = *UpperU ? "U" : "u";
736f7639e1bSTed Kremenek Info.L = *UpperL ? "L" : "l";
737f7639e1bSTed Kremenek Info.LL = *UpperL ? "LL" : "ll";
738f7639e1bSTed Kremenek Info.F = UpperF ? "F" : "f";
739f7639e1bSTed Kremenek
740f7639e1bSTed Kremenek Info.Hex = Info.Octal = false;
741f7639e1bSTed Kremenek if (text.startswith("0x"))
742f7639e1bSTed Kremenek Info.Hex = true;
743f7639e1bSTed Kremenek else if (!isFloat && !isIntZero && text.startswith("0"))
744f7639e1bSTed Kremenek Info.Octal = true;
745f7639e1bSTed Kremenek
746f7639e1bSTed Kremenek SourceLocation B = literalRange.getBegin();
747f7639e1bSTed Kremenek Info.WithoutSuffRange =
748f7639e1bSTed Kremenek CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
749f7639e1bSTed Kremenek return true;
750f7639e1bSTed Kremenek }
751f7639e1bSTed Kremenek
rewriteToNumberLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)752f7639e1bSTed Kremenek static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
753f7639e1bSTed Kremenek const NSAPI &NS, Commit &commit) {
754f7639e1bSTed Kremenek if (Msg->getNumArgs() != 1)
755f7639e1bSTed Kremenek return false;
756f7639e1bSTed Kremenek
757f7639e1bSTed Kremenek const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
758f7639e1bSTed Kremenek if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
759f7639e1bSTed Kremenek return rewriteToCharLiteral(Msg, CharE, NS, commit);
760f7639e1bSTed Kremenek if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
761f7639e1bSTed Kremenek return rewriteToBoolLiteral(Msg, BE, NS, commit);
762f7639e1bSTed Kremenek if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
763f7639e1bSTed Kremenek return rewriteToBoolLiteral(Msg, BE, NS, commit);
764f7639e1bSTed Kremenek
765f7639e1bSTed Kremenek const Expr *literalE = Arg;
766f7639e1bSTed Kremenek if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
767f7639e1bSTed Kremenek if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
768f7639e1bSTed Kremenek literalE = UOE->getSubExpr();
769f7639e1bSTed Kremenek }
770f7639e1bSTed Kremenek
771491e4aedSArgyrios Kyrtzidis // Only integer and floating literals, otherwise try to rewrite to boxed
772491e4aedSArgyrios Kyrtzidis // expression.
773f7639e1bSTed Kremenek if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
774491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
775f7639e1bSTed Kremenek
776f7639e1bSTed Kremenek ASTContext &Ctx = NS.getASTContext();
777f7639e1bSTed Kremenek Selector Sel = Msg->getSelector();
77805785d16SDavid Blaikie Optional<NSAPI::NSNumberLiteralMethodKind>
779f7639e1bSTed Kremenek MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
780f7639e1bSTed Kremenek if (!MKOpt)
781f7639e1bSTed Kremenek return false;
782f7639e1bSTed Kremenek NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
783f7639e1bSTed Kremenek
784ece209afSBenjamin Kramer bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
785f7639e1bSTed Kremenek bool CallIsFloating = false, CallIsDouble = false;
786f7639e1bSTed Kremenek
787f7639e1bSTed Kremenek switch (MK) {
788f7639e1bSTed Kremenek // We cannot have these calls with int/float literals.
789f7639e1bSTed Kremenek case NSAPI::NSNumberWithChar:
790f7639e1bSTed Kremenek case NSAPI::NSNumberWithUnsignedChar:
791f7639e1bSTed Kremenek case NSAPI::NSNumberWithShort:
792f7639e1bSTed Kremenek case NSAPI::NSNumberWithUnsignedShort:
793f7639e1bSTed Kremenek case NSAPI::NSNumberWithBool:
794491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
795f7639e1bSTed Kremenek
796f7639e1bSTed Kremenek case NSAPI::NSNumberWithUnsignedInt:
797f7639e1bSTed Kremenek case NSAPI::NSNumberWithUnsignedInteger:
798f7639e1bSTed Kremenek CallIsUnsigned = true;
799efa71244SGalina Kistanova LLVM_FALLTHROUGH;
800f7639e1bSTed Kremenek case NSAPI::NSNumberWithInt:
801f7639e1bSTed Kremenek case NSAPI::NSNumberWithInteger:
802f7639e1bSTed Kremenek break;
803f7639e1bSTed Kremenek
804f7639e1bSTed Kremenek case NSAPI::NSNumberWithUnsignedLong:
805f7639e1bSTed Kremenek CallIsUnsigned = true;
806efa71244SGalina Kistanova LLVM_FALLTHROUGH;
807f7639e1bSTed Kremenek case NSAPI::NSNumberWithLong:
808ece209afSBenjamin Kramer CallIsLong = true;
809f7639e1bSTed Kremenek break;
810f7639e1bSTed Kremenek
811f7639e1bSTed Kremenek case NSAPI::NSNumberWithUnsignedLongLong:
812f7639e1bSTed Kremenek CallIsUnsigned = true;
813efa71244SGalina Kistanova LLVM_FALLTHROUGH;
814f7639e1bSTed Kremenek case NSAPI::NSNumberWithLongLong:
815ece209afSBenjamin Kramer CallIsLongLong = true;
816f7639e1bSTed Kremenek break;
817f7639e1bSTed Kremenek
818f7639e1bSTed Kremenek case NSAPI::NSNumberWithDouble:
819f7639e1bSTed Kremenek CallIsDouble = true;
820efa71244SGalina Kistanova LLVM_FALLTHROUGH;
821f7639e1bSTed Kremenek case NSAPI::NSNumberWithFloat:
822f7639e1bSTed Kremenek CallIsFloating = true;
823f7639e1bSTed Kremenek break;
824f7639e1bSTed Kremenek }
825f7639e1bSTed Kremenek
826f7639e1bSTed Kremenek SourceRange ArgRange = Arg->getSourceRange();
827f7639e1bSTed Kremenek QualType ArgTy = Arg->getType();
828f7639e1bSTed Kremenek QualType CallTy = Msg->getArg(0)->getType();
829f7639e1bSTed Kremenek
830f7639e1bSTed Kremenek // Check for the easy case, the literal maps directly to the call.
831f7639e1bSTed Kremenek if (Ctx.hasSameType(ArgTy, CallTy)) {
832f7639e1bSTed Kremenek commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
833f7639e1bSTed Kremenek commit.insert(ArgRange.getBegin(), "@");
834f7639e1bSTed Kremenek return true;
835f7639e1bSTed Kremenek }
836f7639e1bSTed Kremenek
837f7639e1bSTed Kremenek // We will need to modify the literal suffix to get the same type as the call.
838491e4aedSArgyrios Kyrtzidis // Try with boxed expression if it came from a macro.
839f7639e1bSTed Kremenek if (ArgRange.getBegin().isMacroID())
840491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
841f7639e1bSTed Kremenek
842f7639e1bSTed Kremenek bool LitIsFloat = ArgTy->isFloatingType();
843491e4aedSArgyrios Kyrtzidis // For a float passed to integer call, don't try rewriting to objc literal.
844491e4aedSArgyrios Kyrtzidis // It is difficult and a very uncommon case anyway.
845491e4aedSArgyrios Kyrtzidis // But try with boxed expression.
846f7639e1bSTed Kremenek if (LitIsFloat && !CallIsFloating)
847491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
848f7639e1bSTed Kremenek
849f7639e1bSTed Kremenek // Try to modify the literal make it the same type as the method call.
850f7639e1bSTed Kremenek // -Modify the suffix, and/or
851f7639e1bSTed Kremenek // -Change integer to float
852f7639e1bSTed Kremenek
853f7639e1bSTed Kremenek LiteralInfo LitInfo;
854f7639e1bSTed Kremenek bool isIntZero = false;
855f7639e1bSTed Kremenek if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
856f7639e1bSTed Kremenek isIntZero = !IntE->getValue().getBoolValue();
857f7639e1bSTed Kremenek if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
858491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
859f7639e1bSTed Kremenek
860f7639e1bSTed Kremenek // Not easy to do int -> float with hex/octal and uncommon anyway.
861f7639e1bSTed Kremenek if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
862491e4aedSArgyrios Kyrtzidis return rewriteToNumericBoxedExpression(Msg, NS, commit);
863f7639e1bSTed Kremenek
864f7639e1bSTed Kremenek SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
865f7639e1bSTed Kremenek SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
866f7639e1bSTed Kremenek
867f7639e1bSTed Kremenek commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
868f7639e1bSTed Kremenek LitInfo.WithoutSuffRange);
869f7639e1bSTed Kremenek commit.insert(LitB, "@");
870f7639e1bSTed Kremenek
871f7639e1bSTed Kremenek if (!LitIsFloat && CallIsFloating)
872f7639e1bSTed Kremenek commit.insert(LitE, ".0");
873f7639e1bSTed Kremenek
874f7639e1bSTed Kremenek if (CallIsFloating) {
875f7639e1bSTed Kremenek if (!CallIsDouble)
876f7639e1bSTed Kremenek commit.insert(LitE, LitInfo.F);
877f7639e1bSTed Kremenek } else {
878f7639e1bSTed Kremenek if (CallIsUnsigned)
879f7639e1bSTed Kremenek commit.insert(LitE, LitInfo.U);
880f7639e1bSTed Kremenek
881f7639e1bSTed Kremenek if (CallIsLong)
882f7639e1bSTed Kremenek commit.insert(LitE, LitInfo.L);
883f7639e1bSTed Kremenek else if (CallIsLongLong)
884f7639e1bSTed Kremenek commit.insert(LitE, LitInfo.LL);
885f7639e1bSTed Kremenek }
886f7639e1bSTed Kremenek return true;
887f7639e1bSTed Kremenek }
888c1dfed65SArgyrios Kyrtzidis
8890bbe94f7SArgyrios Kyrtzidis // FIXME: Make determination of operator precedence more general and
8900bbe94f7SArgyrios Kyrtzidis // make it broadly available.
subscriptOperatorNeedsParens(const Expr * FullExpr)8910bbe94f7SArgyrios Kyrtzidis static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
8920bbe94f7SArgyrios Kyrtzidis const Expr* Expr = FullExpr->IgnoreImpCasts();
8930bbe94f7SArgyrios Kyrtzidis if (isa<ArraySubscriptExpr>(Expr) ||
8940bbe94f7SArgyrios Kyrtzidis isa<CallExpr>(Expr) ||
8950bbe94f7SArgyrios Kyrtzidis isa<DeclRefExpr>(Expr) ||
8960bbe94f7SArgyrios Kyrtzidis isa<CXXNamedCastExpr>(Expr) ||
8970bbe94f7SArgyrios Kyrtzidis isa<CXXConstructExpr>(Expr) ||
8980bbe94f7SArgyrios Kyrtzidis isa<CXXThisExpr>(Expr) ||
8990bbe94f7SArgyrios Kyrtzidis isa<CXXTypeidExpr>(Expr) ||
9000bbe94f7SArgyrios Kyrtzidis isa<CXXUnresolvedConstructExpr>(Expr) ||
9010bbe94f7SArgyrios Kyrtzidis isa<ObjCMessageExpr>(Expr) ||
9020bbe94f7SArgyrios Kyrtzidis isa<ObjCPropertyRefExpr>(Expr) ||
9030bbe94f7SArgyrios Kyrtzidis isa<ObjCProtocolExpr>(Expr) ||
9040bbe94f7SArgyrios Kyrtzidis isa<MemberExpr>(Expr) ||
90594442980SArgyrios Kyrtzidis isa<ObjCIvarRefExpr>(Expr) ||
9060bbe94f7SArgyrios Kyrtzidis isa<ParenExpr>(FullExpr) ||
9070bbe94f7SArgyrios Kyrtzidis isa<ParenListExpr>(Expr) ||
9080bbe94f7SArgyrios Kyrtzidis isa<SizeOfPackExpr>(Expr))
9090bbe94f7SArgyrios Kyrtzidis return false;
9100bbe94f7SArgyrios Kyrtzidis
9110bbe94f7SArgyrios Kyrtzidis return true;
9120bbe94f7SArgyrios Kyrtzidis }
castOperatorNeedsParens(const Expr * FullExpr)913c1dfed65SArgyrios Kyrtzidis static bool castOperatorNeedsParens(const Expr *FullExpr) {
914c1dfed65SArgyrios Kyrtzidis const Expr* Expr = FullExpr->IgnoreImpCasts();
915c1dfed65SArgyrios Kyrtzidis if (isa<ArraySubscriptExpr>(Expr) ||
916c1dfed65SArgyrios Kyrtzidis isa<CallExpr>(Expr) ||
917c1dfed65SArgyrios Kyrtzidis isa<DeclRefExpr>(Expr) ||
918c1dfed65SArgyrios Kyrtzidis isa<CastExpr>(Expr) ||
919c1dfed65SArgyrios Kyrtzidis isa<CXXNewExpr>(Expr) ||
920c1dfed65SArgyrios Kyrtzidis isa<CXXConstructExpr>(Expr) ||
921c1dfed65SArgyrios Kyrtzidis isa<CXXDeleteExpr>(Expr) ||
922c1dfed65SArgyrios Kyrtzidis isa<CXXNoexceptExpr>(Expr) ||
923c1dfed65SArgyrios Kyrtzidis isa<CXXPseudoDestructorExpr>(Expr) ||
924c1dfed65SArgyrios Kyrtzidis isa<CXXScalarValueInitExpr>(Expr) ||
925c1dfed65SArgyrios Kyrtzidis isa<CXXThisExpr>(Expr) ||
926c1dfed65SArgyrios Kyrtzidis isa<CXXTypeidExpr>(Expr) ||
927c1dfed65SArgyrios Kyrtzidis isa<CXXUnresolvedConstructExpr>(Expr) ||
928c1dfed65SArgyrios Kyrtzidis isa<ObjCMessageExpr>(Expr) ||
929c1dfed65SArgyrios Kyrtzidis isa<ObjCPropertyRefExpr>(Expr) ||
930c1dfed65SArgyrios Kyrtzidis isa<ObjCProtocolExpr>(Expr) ||
931c1dfed65SArgyrios Kyrtzidis isa<MemberExpr>(Expr) ||
93294442980SArgyrios Kyrtzidis isa<ObjCIvarRefExpr>(Expr) ||
933c1dfed65SArgyrios Kyrtzidis isa<ParenExpr>(FullExpr) ||
934c1dfed65SArgyrios Kyrtzidis isa<ParenListExpr>(Expr) ||
935c1dfed65SArgyrios Kyrtzidis isa<SizeOfPackExpr>(Expr) ||
936c1dfed65SArgyrios Kyrtzidis isa<UnaryOperator>(Expr))
937c1dfed65SArgyrios Kyrtzidis return false;
938c1dfed65SArgyrios Kyrtzidis
939c1dfed65SArgyrios Kyrtzidis return true;
940c1dfed65SArgyrios Kyrtzidis }
941c1dfed65SArgyrios Kyrtzidis
objectifyExpr(const Expr * E,Commit & commit)942c1dfed65SArgyrios Kyrtzidis static void objectifyExpr(const Expr *E, Commit &commit) {
943c1dfed65SArgyrios Kyrtzidis if (!E) return;
944c1dfed65SArgyrios Kyrtzidis
945c1dfed65SArgyrios Kyrtzidis QualType T = E->getType();
946c1dfed65SArgyrios Kyrtzidis if (T->isObjCObjectPointerType()) {
947c1dfed65SArgyrios Kyrtzidis if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
948c1dfed65SArgyrios Kyrtzidis if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
949c1dfed65SArgyrios Kyrtzidis return;
950c1dfed65SArgyrios Kyrtzidis } else {
951c1dfed65SArgyrios Kyrtzidis return;
952c1dfed65SArgyrios Kyrtzidis }
953c1dfed65SArgyrios Kyrtzidis } else if (!T->isPointerType()) {
954c1dfed65SArgyrios Kyrtzidis return;
955c1dfed65SArgyrios Kyrtzidis }
956c1dfed65SArgyrios Kyrtzidis
957c1dfed65SArgyrios Kyrtzidis SourceRange Range = E->getSourceRange();
958c1dfed65SArgyrios Kyrtzidis if (castOperatorNeedsParens(E))
959c1dfed65SArgyrios Kyrtzidis commit.insertWrap("(", Range, ")");
960c1dfed65SArgyrios Kyrtzidis commit.insertBefore(Range.getBegin(), "(id)");
961c1dfed65SArgyrios Kyrtzidis }
962491e4aedSArgyrios Kyrtzidis
963491e4aedSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
964491e4aedSArgyrios Kyrtzidis // rewriteToNumericBoxedExpression.
965491e4aedSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
966491e4aedSArgyrios Kyrtzidis
isEnumConstant(const Expr * E)967cebe722eSArgyrios Kyrtzidis static bool isEnumConstant(const Expr *E) {
968cebe722eSArgyrios Kyrtzidis if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
969cebe722eSArgyrios Kyrtzidis if (const ValueDecl *VD = DRE->getDecl())
970cebe722eSArgyrios Kyrtzidis return isa<EnumConstantDecl>(VD);
971cebe722eSArgyrios Kyrtzidis
972cebe722eSArgyrios Kyrtzidis return false;
973cebe722eSArgyrios Kyrtzidis }
974cebe722eSArgyrios Kyrtzidis
rewriteToNumericBoxedExpression(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)975491e4aedSArgyrios Kyrtzidis static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
976491e4aedSArgyrios Kyrtzidis const NSAPI &NS, Commit &commit) {
977491e4aedSArgyrios Kyrtzidis if (Msg->getNumArgs() != 1)
978491e4aedSArgyrios Kyrtzidis return false;
979491e4aedSArgyrios Kyrtzidis
980491e4aedSArgyrios Kyrtzidis const Expr *Arg = Msg->getArg(0);
981491e4aedSArgyrios Kyrtzidis if (Arg->isTypeDependent())
982491e4aedSArgyrios Kyrtzidis return false;
983491e4aedSArgyrios Kyrtzidis
984491e4aedSArgyrios Kyrtzidis ASTContext &Ctx = NS.getASTContext();
985491e4aedSArgyrios Kyrtzidis Selector Sel = Msg->getSelector();
98605785d16SDavid Blaikie Optional<NSAPI::NSNumberLiteralMethodKind>
987491e4aedSArgyrios Kyrtzidis MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
988491e4aedSArgyrios Kyrtzidis if (!MKOpt)
989491e4aedSArgyrios Kyrtzidis return false;
990491e4aedSArgyrios Kyrtzidis NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
991491e4aedSArgyrios Kyrtzidis
992491e4aedSArgyrios Kyrtzidis const Expr *OrigArg = Arg->IgnoreImpCasts();
993491e4aedSArgyrios Kyrtzidis QualType FinalTy = Arg->getType();
994491e4aedSArgyrios Kyrtzidis QualType OrigTy = OrigArg->getType();
995491e4aedSArgyrios Kyrtzidis uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
996491e4aedSArgyrios Kyrtzidis uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
997491e4aedSArgyrios Kyrtzidis
998491e4aedSArgyrios Kyrtzidis bool isTruncated = FinalTySize < OrigTySize;
999491e4aedSArgyrios Kyrtzidis bool needsCast = false;
1000491e4aedSArgyrios Kyrtzidis
1001491e4aedSArgyrios Kyrtzidis if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
1002491e4aedSArgyrios Kyrtzidis switch (ICE->getCastKind()) {
1003491e4aedSArgyrios Kyrtzidis case CK_LValueToRValue:
1004491e4aedSArgyrios Kyrtzidis case CK_NoOp:
1005491e4aedSArgyrios Kyrtzidis case CK_UserDefinedConversion:
1006491e4aedSArgyrios Kyrtzidis break;
1007491e4aedSArgyrios Kyrtzidis
1008491e4aedSArgyrios Kyrtzidis case CK_IntegralCast: {
1009491e4aedSArgyrios Kyrtzidis if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
1010491e4aedSArgyrios Kyrtzidis break;
1011491e4aedSArgyrios Kyrtzidis // Be more liberal with Integer/UnsignedInteger which are very commonly
1012491e4aedSArgyrios Kyrtzidis // used.
1013491e4aedSArgyrios Kyrtzidis if ((MK == NSAPI::NSNumberWithInteger ||
1014491e4aedSArgyrios Kyrtzidis MK == NSAPI::NSNumberWithUnsignedInteger) &&
1015491e4aedSArgyrios Kyrtzidis !isTruncated) {
1016cebe722eSArgyrios Kyrtzidis if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
1017491e4aedSArgyrios Kyrtzidis break;
1018491e4aedSArgyrios Kyrtzidis if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
1019491e4aedSArgyrios Kyrtzidis OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
1020491e4aedSArgyrios Kyrtzidis break;
1021491e4aedSArgyrios Kyrtzidis }
1022491e4aedSArgyrios Kyrtzidis
1023491e4aedSArgyrios Kyrtzidis needsCast = true;
1024491e4aedSArgyrios Kyrtzidis break;
1025491e4aedSArgyrios Kyrtzidis }
1026491e4aedSArgyrios Kyrtzidis
1027491e4aedSArgyrios Kyrtzidis case CK_PointerToBoolean:
1028491e4aedSArgyrios Kyrtzidis case CK_IntegralToBoolean:
1029491e4aedSArgyrios Kyrtzidis case CK_IntegralToFloating:
1030491e4aedSArgyrios Kyrtzidis case CK_FloatingToIntegral:
1031491e4aedSArgyrios Kyrtzidis case CK_FloatingToBoolean:
1032491e4aedSArgyrios Kyrtzidis case CK_FloatingCast:
1033491e4aedSArgyrios Kyrtzidis case CK_FloatingComplexToReal:
1034491e4aedSArgyrios Kyrtzidis case CK_FloatingComplexToBoolean:
1035491e4aedSArgyrios Kyrtzidis case CK_IntegralComplexToReal:
1036491e4aedSArgyrios Kyrtzidis case CK_IntegralComplexToBoolean:
1037491e4aedSArgyrios Kyrtzidis case CK_AtomicToNonAtomic:
1038e1468322SDavid Tweed case CK_AddressSpaceConversion:
1039491e4aedSArgyrios Kyrtzidis needsCast = true;
1040491e4aedSArgyrios Kyrtzidis break;
1041491e4aedSArgyrios Kyrtzidis
1042491e4aedSArgyrios Kyrtzidis case CK_Dependent:
1043491e4aedSArgyrios Kyrtzidis case CK_BitCast:
1044491e4aedSArgyrios Kyrtzidis case CK_LValueBitCast:
1045eee944e7SErik Pilkington case CK_LValueToRValueBitCast:
1046491e4aedSArgyrios Kyrtzidis case CK_BaseToDerived:
1047491e4aedSArgyrios Kyrtzidis case CK_DerivedToBase:
1048491e4aedSArgyrios Kyrtzidis case CK_UncheckedDerivedToBase:
1049491e4aedSArgyrios Kyrtzidis case CK_Dynamic:
1050491e4aedSArgyrios Kyrtzidis case CK_ToUnion:
1051491e4aedSArgyrios Kyrtzidis case CK_ArrayToPointerDecay:
1052491e4aedSArgyrios Kyrtzidis case CK_FunctionToPointerDecay:
1053491e4aedSArgyrios Kyrtzidis case CK_NullToPointer:
1054491e4aedSArgyrios Kyrtzidis case CK_NullToMemberPointer:
1055491e4aedSArgyrios Kyrtzidis case CK_BaseToDerivedMemberPointer:
1056491e4aedSArgyrios Kyrtzidis case CK_DerivedToBaseMemberPointer:
1057491e4aedSArgyrios Kyrtzidis case CK_MemberPointerToBoolean:
1058491e4aedSArgyrios Kyrtzidis case CK_ReinterpretMemberPointer:
1059491e4aedSArgyrios Kyrtzidis case CK_ConstructorConversion:
1060491e4aedSArgyrios Kyrtzidis case CK_IntegralToPointer:
1061491e4aedSArgyrios Kyrtzidis case CK_PointerToIntegral:
1062491e4aedSArgyrios Kyrtzidis case CK_ToVoid:
1063491e4aedSArgyrios Kyrtzidis case CK_VectorSplat:
1064491e4aedSArgyrios Kyrtzidis case CK_CPointerToObjCPointerCast:
1065491e4aedSArgyrios Kyrtzidis case CK_BlockPointerToObjCPointerCast:
1066491e4aedSArgyrios Kyrtzidis case CK_AnyPointerToBlockPointerCast:
1067491e4aedSArgyrios Kyrtzidis case CK_ObjCObjectLValueCast:
1068491e4aedSArgyrios Kyrtzidis case CK_FloatingRealToComplex:
1069491e4aedSArgyrios Kyrtzidis case CK_FloatingComplexCast:
1070491e4aedSArgyrios Kyrtzidis case CK_FloatingComplexToIntegralComplex:
1071491e4aedSArgyrios Kyrtzidis case CK_IntegralRealToComplex:
1072491e4aedSArgyrios Kyrtzidis case CK_IntegralComplexCast:
1073491e4aedSArgyrios Kyrtzidis case CK_IntegralComplexToFloatingComplex:
1074491e4aedSArgyrios Kyrtzidis case CK_ARCProduceObject:
1075491e4aedSArgyrios Kyrtzidis case CK_ARCConsumeObject:
1076491e4aedSArgyrios Kyrtzidis case CK_ARCReclaimReturnedObject:
1077491e4aedSArgyrios Kyrtzidis case CK_ARCExtendBlockObject:
1078491e4aedSArgyrios Kyrtzidis case CK_NonAtomicToAtomic:
1079491e4aedSArgyrios Kyrtzidis case CK_CopyAndAutoreleaseBlockObject:
108034866c77SEli Friedman case CK_BuiltinFnToFnPtr:
1081b555b76eSAndrew Savonichev case CK_ZeroToOCLOpaqueType:
10820bc4b2d3SYaxun Liu case CK_IntToOCLSampler:
108371ab6c98SSaurabh Jha case CK_MatrixCast:
1084491e4aedSArgyrios Kyrtzidis return false;
1085df1ed009SGeorge Burgess IV
1086df1ed009SGeorge Burgess IV case CK_BooleanToSignedIntegral:
1087df1ed009SGeorge Burgess IV llvm_unreachable("OpenCL-specific cast in Objective-C?");
108899bda375SLeonard Chan
10899fa7f484SBevin Hansson case CK_FloatingToFixedPoint:
10909fa7f484SBevin Hansson case CK_FixedPointToFloating:
109199bda375SLeonard Chan case CK_FixedPointCast:
1092b4ba467dSLeonard Chan case CK_FixedPointToBoolean:
10938f7caae0SLeonard Chan case CK_FixedPointToIntegral:
10948f7caae0SLeonard Chan case CK_IntegralToFixedPoint:
109599bda375SLeonard Chan llvm_unreachable("Fixed point types are disabled for Objective-C");
1096491e4aedSArgyrios Kyrtzidis }
1097491e4aedSArgyrios Kyrtzidis }
1098491e4aedSArgyrios Kyrtzidis
1099b4822607SArgyrios Kyrtzidis if (needsCast) {
1100b4822607SArgyrios Kyrtzidis DiagnosticsEngine &Diags = Ctx.getDiagnostics();
1101b4822607SArgyrios Kyrtzidis // FIXME: Use a custom category name to distinguish migration diagnostics.
1102b4822607SArgyrios Kyrtzidis unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
1103927a437aSArgyrios Kyrtzidis "converting to boxing syntax requires casting %0 to %1");
1104927a437aSArgyrios Kyrtzidis Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
1105927a437aSArgyrios Kyrtzidis << Msg->getSourceRange();
1106491e4aedSArgyrios Kyrtzidis return false;
1107b4822607SArgyrios Kyrtzidis }
1108491e4aedSArgyrios Kyrtzidis
1109491e4aedSArgyrios Kyrtzidis SourceRange ArgRange = OrigArg->getSourceRange();
11107bd957c1SArgyrios Kyrtzidis commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1111491e4aedSArgyrios Kyrtzidis
1112491e4aedSArgyrios Kyrtzidis if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1113491e4aedSArgyrios Kyrtzidis commit.insertBefore(ArgRange.getBegin(), "@");
1114491e4aedSArgyrios Kyrtzidis else
1115491e4aedSArgyrios Kyrtzidis commit.insertWrap("@(", ArgRange, ")");
1116491e4aedSArgyrios Kyrtzidis
1117491e4aedSArgyrios Kyrtzidis return true;
1118491e4aedSArgyrios Kyrtzidis }
11197bd957c1SArgyrios Kyrtzidis
11207bd957c1SArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
11217bd957c1SArgyrios Kyrtzidis // rewriteToStringBoxedExpression.
11227bd957c1SArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
11237bd957c1SArgyrios Kyrtzidis
doRewriteToUTF8StringBoxedExpressionHelper(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)11247bd957c1SArgyrios Kyrtzidis static bool doRewriteToUTF8StringBoxedExpressionHelper(
11257bd957c1SArgyrios Kyrtzidis const ObjCMessageExpr *Msg,
11267bd957c1SArgyrios Kyrtzidis const NSAPI &NS, Commit &commit) {
11277bd957c1SArgyrios Kyrtzidis const Expr *Arg = Msg->getArg(0);
11287bd957c1SArgyrios Kyrtzidis if (Arg->isTypeDependent())
11297bd957c1SArgyrios Kyrtzidis return false;
11307bd957c1SArgyrios Kyrtzidis
113181541479SArgyrios Kyrtzidis ASTContext &Ctx = NS.getASTContext();
113281541479SArgyrios Kyrtzidis
11337bd957c1SArgyrios Kyrtzidis const Expr *OrigArg = Arg->IgnoreImpCasts();
11347bd957c1SArgyrios Kyrtzidis QualType OrigTy = OrigArg->getType();
113581541479SArgyrios Kyrtzidis if (OrigTy->isArrayType())
113681541479SArgyrios Kyrtzidis OrigTy = Ctx.getArrayDecayedType(OrigTy);
11377bd957c1SArgyrios Kyrtzidis
11387bd957c1SArgyrios Kyrtzidis if (const StringLiteral *
11397bd957c1SArgyrios Kyrtzidis StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
11407bd957c1SArgyrios Kyrtzidis commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
1141f2ceec48SStephen Kelly commit.insert(StrE->getBeginLoc(), "@");
11427bd957c1SArgyrios Kyrtzidis return true;
11437bd957c1SArgyrios Kyrtzidis }
11447bd957c1SArgyrios Kyrtzidis
11457bd957c1SArgyrios Kyrtzidis if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
11467bd957c1SArgyrios Kyrtzidis QualType PointeeType = PT->getPointeeType();
11477bd957c1SArgyrios Kyrtzidis if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
11487bd957c1SArgyrios Kyrtzidis SourceRange ArgRange = OrigArg->getSourceRange();
11497bd957c1SArgyrios Kyrtzidis commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
11507bd957c1SArgyrios Kyrtzidis
11517bd957c1SArgyrios Kyrtzidis if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
11527bd957c1SArgyrios Kyrtzidis commit.insertBefore(ArgRange.getBegin(), "@");
11537bd957c1SArgyrios Kyrtzidis else
11547bd957c1SArgyrios Kyrtzidis commit.insertWrap("@(", ArgRange, ")");
11557bd957c1SArgyrios Kyrtzidis
11567bd957c1SArgyrios Kyrtzidis return true;
11577bd957c1SArgyrios Kyrtzidis }
11587bd957c1SArgyrios Kyrtzidis }
11597bd957c1SArgyrios Kyrtzidis
11607bd957c1SArgyrios Kyrtzidis return false;
11617bd957c1SArgyrios Kyrtzidis }
11627bd957c1SArgyrios Kyrtzidis
rewriteToStringBoxedExpression(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)11637bd957c1SArgyrios Kyrtzidis static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
11647bd957c1SArgyrios Kyrtzidis const NSAPI &NS, Commit &commit) {
11657bd957c1SArgyrios Kyrtzidis Selector Sel = Msg->getSelector();
11667bd957c1SArgyrios Kyrtzidis
11677bd957c1SArgyrios Kyrtzidis if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
1168be7bf728SFariborz Jahanian Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString) ||
1169be7bf728SFariborz Jahanian Sel == NS.getNSStringSelector(NSAPI::NSStr_initWithUTF8String)) {
11707bd957c1SArgyrios Kyrtzidis if (Msg->getNumArgs() != 1)
11717bd957c1SArgyrios Kyrtzidis return false;
11727bd957c1SArgyrios Kyrtzidis return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
11737bd957c1SArgyrios Kyrtzidis }
11747bd957c1SArgyrios Kyrtzidis
11757bd957c1SArgyrios Kyrtzidis if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
11767bd957c1SArgyrios Kyrtzidis if (Msg->getNumArgs() != 2)
11777bd957c1SArgyrios Kyrtzidis return false;
11787bd957c1SArgyrios Kyrtzidis
11797bd957c1SArgyrios Kyrtzidis const Expr *encodingArg = Msg->getArg(1);
11807bd957c1SArgyrios Kyrtzidis if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
11817bd957c1SArgyrios Kyrtzidis NS.isNSASCIIStringEncodingConstant(encodingArg))
11827bd957c1SArgyrios Kyrtzidis return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
11837bd957c1SArgyrios Kyrtzidis }
11847bd957c1SArgyrios Kyrtzidis
11857bd957c1SArgyrios Kyrtzidis return false;
11867bd957c1SArgyrios Kyrtzidis }
1187