12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187 |
- //===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Rewrites legacy method calls to modern syntax.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Edit/Rewriters.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/ExprCXX.h"
- #include "clang/AST/ExprObjC.h"
- #include "clang/AST/NSAPI.h"
- #include "clang/AST/ParentMap.h"
- #include "clang/Edit/Commit.h"
- #include "clang/Lex/Lexer.h"
- #include <optional>
- using namespace clang;
- using namespace edit;
- static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
- IdentifierInfo *&ClassId,
- const LangOptions &LangOpts) {
- if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
- return false;
- const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
- if (!Receiver)
- return false;
- ClassId = Receiver->getIdentifier();
- if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
- return true;
- // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
- // since the change from +1 to +0 will be handled fine by ARC.
- if (LangOpts.ObjCAutoRefCount) {
- if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
- if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
- Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
- if (Rec->getMethodFamily() == OMF_alloc)
- return true;
- }
- }
- }
- return false;
- }
- //===----------------------------------------------------------------------===//
- // rewriteObjCRedundantCallWithLiteral.
- //===----------------------------------------------------------------------===//
- bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
- IdentifierInfo *II = nullptr;
- if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
- return false;
- if (Msg->getNumArgs() != 1)
- return false;
- const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
- Selector Sel = Msg->getSelector();
- if ((isa<ObjCStringLiteral>(Arg) &&
- NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
- (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
- NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel)) ||
- (isa<ObjCArrayLiteral>(Arg) &&
- NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
- (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
- NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel)) ||
- (isa<ObjCDictionaryLiteral>(Arg) &&
- NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
- (NS.getNSDictionarySelector(
- NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
- NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
- commit.replaceWithInner(Msg->getSourceRange(),
- Msg->getArg(0)->getSourceRange());
- return true;
- }
- return false;
- }
- //===----------------------------------------------------------------------===//
- // rewriteToObjCSubscriptSyntax.
- //===----------------------------------------------------------------------===//
- /// Check for classes that accept 'objectForKey:' (or the other selectors
- /// that the migrator handles) but return their instances as 'id', resulting
- /// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
- ///
- /// When checking if we can convert to subscripting syntax, check whether
- /// the receiver is a result of a class method from a hardcoded list of
- /// such classes. In such a case return the specific class as the interface
- /// of the receiver.
- ///
- /// FIXME: Remove this when these classes start using 'instancetype'.
- static const ObjCInterfaceDecl *
- maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
- const Expr *Receiver,
- ASTContext &Ctx) {
- assert(IFace && Receiver);
- // If the receiver has type 'id'...
- if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
- return IFace;
- const ObjCMessageExpr *
- InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
- if (!InnerMsg)
- return IFace;
- QualType ClassRec;
- switch (InnerMsg->getReceiverKind()) {
- case ObjCMessageExpr::Instance:
- case ObjCMessageExpr::SuperInstance:
- return IFace;
- case ObjCMessageExpr::Class:
- ClassRec = InnerMsg->getClassReceiver();
- break;
- case ObjCMessageExpr::SuperClass:
- ClassRec = InnerMsg->getSuperType();
- break;
- }
- if (ClassRec.isNull())
- return IFace;
- // ...and it is the result of a class message...
- const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
- if (!ObjTy)
- return IFace;
- const ObjCInterfaceDecl *OID = ObjTy->getInterface();
- // ...and the receiving class is NSMapTable or NSLocale, return that
- // class as the receiving interface.
- if (OID->getName() == "NSMapTable" ||
- OID->getName() == "NSLocale")
- return OID;
- return IFace;
- }
- static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
- const ObjCMessageExpr *Msg,
- ASTContext &Ctx,
- Selector subscriptSel) {
- const Expr *Rec = Msg->getInstanceReceiver();
- if (!Rec)
- return false;
- IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
- if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
- if (!MD->isUnavailable())
- return true;
- }
- return false;
- }
- static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
- static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
- if (subscriptOperatorNeedsParens(Receiver)) {
- SourceRange RecRange = Receiver->getSourceRange();
- commit.insertWrap("(", RecRange, ")");
- }
- }
- static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
- Commit &commit) {
- if (Msg->getNumArgs() != 1)
- return false;
- const Expr *Rec = Msg->getInstanceReceiver();
- if (!Rec)
- return false;
- SourceRange MsgRange = Msg->getSourceRange();
- SourceRange RecRange = Rec->getSourceRange();
- SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
- commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
- ArgRange.getBegin()),
- CharSourceRange::getTokenRange(RecRange));
- commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
- ArgRange);
- commit.insertWrap("[", ArgRange, "]");
- maybePutParensOnReceiver(Rec, commit);
- return true;
- }
- static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
- const ObjCMessageExpr *Msg,
- const NSAPI &NS,
- Commit &commit) {
- if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
- NS.getObjectAtIndexedSubscriptSelector()))
- return false;
- return rewriteToSubscriptGetCommon(Msg, commit);
- }
- static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
- const ObjCMessageExpr *Msg,
- const NSAPI &NS,
- Commit &commit) {
- if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
- NS.getObjectForKeyedSubscriptSelector()))
- return false;
- return rewriteToSubscriptGetCommon(Msg, commit);
- }
- static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
- const ObjCMessageExpr *Msg,
- const NSAPI &NS,
- Commit &commit) {
- if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
- NS.getSetObjectAtIndexedSubscriptSelector()))
- return false;
- if (Msg->getNumArgs() != 2)
- return false;
- const Expr *Rec = Msg->getInstanceReceiver();
- if (!Rec)
- return false;
- SourceRange MsgRange = Msg->getSourceRange();
- SourceRange RecRange = Rec->getSourceRange();
- SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
- SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
- commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
- Arg0Range.getBegin()),
- CharSourceRange::getTokenRange(RecRange));
- commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
- Arg1Range.getBegin()),
- CharSourceRange::getTokenRange(Arg0Range));
- commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
- Arg1Range);
- commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
- Arg1Range.getBegin()),
- "] = ");
- maybePutParensOnReceiver(Rec, commit);
- return true;
- }
- static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
- const ObjCMessageExpr *Msg,
- const NSAPI &NS,
- Commit &commit) {
- if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
- NS.getSetObjectForKeyedSubscriptSelector()))
- return false;
- if (Msg->getNumArgs() != 2)
- return false;
- const Expr *Rec = Msg->getInstanceReceiver();
- if (!Rec)
- return false;
- SourceRange MsgRange = Msg->getSourceRange();
- SourceRange RecRange = Rec->getSourceRange();
- SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
- SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
- SourceLocation LocBeforeVal = Arg0Range.getBegin();
- commit.insertBefore(LocBeforeVal, "] = ");
- commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
- /*beforePreviousInsertions=*/true);
- commit.insertBefore(LocBeforeVal, "[");
- commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
- Arg0Range.getBegin()),
- CharSourceRange::getTokenRange(RecRange));
- commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
- Arg0Range);
- maybePutParensOnReceiver(Rec, commit);
- return true;
- }
- bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
- if (!Msg || Msg->isImplicit() ||
- Msg->getReceiverKind() != ObjCMessageExpr::Instance)
- return false;
- const ObjCMethodDecl *Method = Msg->getMethodDecl();
- if (!Method)
- return false;
- const ObjCInterfaceDecl *IFace =
- NS.getASTContext().getObjContainingInterface(Method);
- if (!IFace)
- return false;
- Selector Sel = Msg->getSelector();
- if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
- return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
- if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
- return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
- if (Msg->getNumArgs() != 2)
- return false;
- if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
- return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
- if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
- return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
- return false;
- }
- //===----------------------------------------------------------------------===//
- // rewriteToObjCLiteralSyntax.
- //===----------------------------------------------------------------------===//
- static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit,
- const ParentMap *PMap);
- static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
- static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
- static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
- static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
- bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit,
- const ParentMap *PMap) {
- IdentifierInfo *II = nullptr;
- if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
- return false;
- if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
- return rewriteToArrayLiteral(Msg, NS, commit, PMap);
- if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
- return rewriteToDictionaryLiteral(Msg, NS, commit);
- if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
- return rewriteToNumberLiteral(Msg, NS, commit);
- if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
- return rewriteToStringBoxedExpression(Msg, NS, commit);
- return false;
- }
- /// Returns true if the immediate message arguments of \c Msg should not
- /// be rewritten because it will interfere with the rewrite of the parent
- /// message expression. e.g.
- /// \code
- /// [NSDictionary dictionaryWithObjects:
- /// [NSArray arrayWithObjects:@"1", @"2", nil]
- /// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
- /// \endcode
- /// It will return true for this because we are going to rewrite this directly
- /// to a dictionary literal without any array literals.
- static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
- const NSAPI &NS);
- //===----------------------------------------------------------------------===//
- // rewriteToArrayLiteral.
- //===----------------------------------------------------------------------===//
- /// Adds an explicit cast to 'id' if the type is not objc object.
- static void objectifyExpr(const Expr *E, Commit &commit);
- static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit,
- const ParentMap *PMap) {
- if (PMap) {
- const ObjCMessageExpr *ParentMsg =
- dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
- if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
- return false;
- }
- Selector Sel = Msg->getSelector();
- SourceRange MsgRange = Msg->getSourceRange();
- if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
- if (Msg->getNumArgs() != 0)
- return false;
- commit.replace(MsgRange, "@[]");
- return true;
- }
- if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
- if (Msg->getNumArgs() != 1)
- return false;
- objectifyExpr(Msg->getArg(0), commit);
- SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
- commit.replaceWithInner(MsgRange, ArgRange);
- commit.insertWrap("@[", ArgRange, "]");
- return true;
- }
- if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
- Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
- if (Msg->getNumArgs() == 0)
- return false;
- const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
- if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
- return false;
- for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
- objectifyExpr(Msg->getArg(i), commit);
- if (Msg->getNumArgs() == 1) {
- commit.replace(MsgRange, "@[]");
- return true;
- }
- SourceRange ArgRange(Msg->getArg(0)->getBeginLoc(),
- Msg->getArg(Msg->getNumArgs() - 2)->getEndLoc());
- commit.replaceWithInner(MsgRange, ArgRange);
- commit.insertWrap("@[", ArgRange, "]");
- return true;
- }
- return false;
- }
- //===----------------------------------------------------------------------===//
- // rewriteToDictionaryLiteral.
- //===----------------------------------------------------------------------===//
- /// If \c Msg is an NSArray creation message or literal, this gets the
- /// objects that were used to create it.
- /// \returns true if it is an NSArray and we got objects, or false otherwise.
- static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
- SmallVectorImpl<const Expr *> &Objs) {
- if (!E)
- return false;
- E = E->IgnoreParenCasts();
- if (!E)
- return false;
- if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
- IdentifierInfo *Cls = nullptr;
- if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
- return false;
- if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
- return false;
- Selector Sel = Msg->getSelector();
- if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
- return true; // empty array.
- if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
- if (Msg->getNumArgs() != 1)
- return false;
- Objs.push_back(Msg->getArg(0));
- return true;
- }
- if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
- Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
- if (Msg->getNumArgs() == 0)
- return false;
- const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
- if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
- return false;
- for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
- Objs.push_back(Msg->getArg(i));
- return true;
- }
- } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
- for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
- Objs.push_back(ArrLit->getElement(i));
- return true;
- }
- return false;
- }
- static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
- Selector Sel = Msg->getSelector();
- SourceRange MsgRange = Msg->getSourceRange();
- if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
- if (Msg->getNumArgs() != 0)
- return false;
- commit.replace(MsgRange, "@{}");
- return true;
- }
- if (Sel == NS.getNSDictionarySelector(
- NSAPI::NSDict_dictionaryWithObjectForKey)) {
- if (Msg->getNumArgs() != 2)
- return false;
- objectifyExpr(Msg->getArg(0), commit);
- objectifyExpr(Msg->getArg(1), commit);
- SourceRange ValRange = Msg->getArg(0)->getSourceRange();
- SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
- // Insert key before the value.
- commit.insertBefore(ValRange.getBegin(), ": ");
- commit.insertFromRange(ValRange.getBegin(),
- CharSourceRange::getTokenRange(KeyRange),
- /*afterToken=*/false, /*beforePreviousInsertions=*/true);
- commit.insertBefore(ValRange.getBegin(), "@{");
- commit.insertAfterToken(ValRange.getEnd(), "}");
- commit.replaceWithInner(MsgRange, ValRange);
- return true;
- }
- if (Sel == NS.getNSDictionarySelector(
- NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
- Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
- if (Msg->getNumArgs() % 2 != 1)
- return false;
- unsigned SentinelIdx = Msg->getNumArgs() - 1;
- const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
- if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
- return false;
- if (Msg->getNumArgs() == 1) {
- commit.replace(MsgRange, "@{}");
- return true;
- }
- for (unsigned i = 0; i < SentinelIdx; i += 2) {
- objectifyExpr(Msg->getArg(i), commit);
- objectifyExpr(Msg->getArg(i+1), commit);
- SourceRange ValRange = Msg->getArg(i)->getSourceRange();
- SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
- // Insert value after key.
- commit.insertAfterToken(KeyRange.getEnd(), ": ");
- commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
- commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
- KeyRange.getBegin()));
- }
- // Range of arguments up until and including the last key.
- // The sentinel and first value are cut off, the value will move after the
- // key.
- SourceRange ArgRange(Msg->getArg(1)->getBeginLoc(),
- Msg->getArg(SentinelIdx - 1)->getEndLoc());
- commit.insertWrap("@{", ArgRange, "}");
- commit.replaceWithInner(MsgRange, ArgRange);
- return true;
- }
- if (Sel == NS.getNSDictionarySelector(
- NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
- Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
- if (Msg->getNumArgs() != 2)
- return false;
- SmallVector<const Expr *, 8> Vals;
- if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
- return false;
- SmallVector<const Expr *, 8> Keys;
- if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
- return false;
- if (Vals.size() != Keys.size())
- return false;
- if (Vals.empty()) {
- commit.replace(MsgRange, "@{}");
- return true;
- }
- for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
- objectifyExpr(Vals[i], commit);
- objectifyExpr(Keys[i], commit);
- SourceRange ValRange = Vals[i]->getSourceRange();
- SourceRange KeyRange = Keys[i]->getSourceRange();
- // Insert value after key.
- commit.insertAfterToken(KeyRange.getEnd(), ": ");
- commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
- }
- // Range of arguments up until and including the last key.
- // The first value is cut off, the value will move after the key.
- SourceRange ArgRange(Keys.front()->getBeginLoc(), Keys.back()->getEndLoc());
- commit.insertWrap("@{", ArgRange, "}");
- commit.replaceWithInner(MsgRange, ArgRange);
- return true;
- }
- return false;
- }
- static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
- const NSAPI &NS) {
- if (!Msg)
- return false;
- IdentifierInfo *II = nullptr;
- if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
- return false;
- if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
- return false;
- Selector Sel = Msg->getSelector();
- if (Sel == NS.getNSDictionarySelector(
- NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
- Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
- if (Msg->getNumArgs() != 2)
- return false;
- SmallVector<const Expr *, 8> Vals;
- if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
- return false;
- SmallVector<const Expr *, 8> Keys;
- if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
- return false;
- if (Vals.size() != Keys.size())
- return false;
- return true;
- }
- return false;
- }
- //===----------------------------------------------------------------------===//
- // rewriteToNumberLiteral.
- //===----------------------------------------------------------------------===//
- static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
- const CharacterLiteral *Arg,
- const NSAPI &NS, Commit &commit) {
- if (Arg->getKind() != CharacterLiteral::Ascii)
- return false;
- if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
- Msg->getSelector())) {
- SourceRange ArgRange = Arg->getSourceRange();
- commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
- commit.insert(ArgRange.getBegin(), "@");
- return true;
- }
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- }
- static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
- const Expr *Arg,
- const NSAPI &NS, Commit &commit) {
- if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
- Msg->getSelector())) {
- SourceRange ArgRange = Arg->getSourceRange();
- commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
- commit.insert(ArgRange.getBegin(), "@");
- return true;
- }
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- }
- namespace {
- struct LiteralInfo {
- bool Hex, Octal;
- StringRef U, F, L, LL;
- CharSourceRange WithoutSuffRange;
- };
- }
- static bool getLiteralInfo(SourceRange literalRange,
- bool isFloat, bool isIntZero,
- ASTContext &Ctx, LiteralInfo &Info) {
- if (literalRange.getBegin().isMacroID() ||
- literalRange.getEnd().isMacroID())
- return false;
- StringRef text = Lexer::getSourceText(
- CharSourceRange::getTokenRange(literalRange),
- Ctx.getSourceManager(), Ctx.getLangOpts());
- if (text.empty())
- return false;
- std::optional<bool> UpperU, UpperL;
- bool UpperF = false;
- struct Suff {
- static bool has(StringRef suff, StringRef &text) {
- if (text.endswith(suff)) {
- text = text.substr(0, text.size()-suff.size());
- return true;
- }
- return false;
- }
- };
- while (true) {
- if (Suff::has("u", text)) {
- UpperU = false;
- } else if (Suff::has("U", text)) {
- UpperU = true;
- } else if (Suff::has("ll", text)) {
- UpperL = false;
- } else if (Suff::has("LL", text)) {
- UpperL = true;
- } else if (Suff::has("l", text)) {
- UpperL = false;
- } else if (Suff::has("L", text)) {
- UpperL = true;
- } else if (isFloat && Suff::has("f", text)) {
- UpperF = false;
- } else if (isFloat && Suff::has("F", text)) {
- UpperF = true;
- } else
- break;
- }
- if (!UpperU && !UpperL)
- UpperU = UpperL = true;
- else if (UpperU && !UpperL)
- UpperL = UpperU;
- else if (UpperL && !UpperU)
- UpperU = UpperL;
- Info.U = *UpperU ? "U" : "u";
- Info.L = *UpperL ? "L" : "l";
- Info.LL = *UpperL ? "LL" : "ll";
- Info.F = UpperF ? "F" : "f";
- Info.Hex = Info.Octal = false;
- if (text.startswith("0x"))
- Info.Hex = true;
- else if (!isFloat && !isIntZero && text.startswith("0"))
- Info.Octal = true;
- SourceLocation B = literalRange.getBegin();
- Info.WithoutSuffRange =
- CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
- return true;
- }
- static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
- if (Msg->getNumArgs() != 1)
- return false;
- const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
- if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
- return rewriteToCharLiteral(Msg, CharE, NS, commit);
- if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
- return rewriteToBoolLiteral(Msg, BE, NS, commit);
- if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
- return rewriteToBoolLiteral(Msg, BE, NS, commit);
- const Expr *literalE = Arg;
- if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
- if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
- literalE = UOE->getSubExpr();
- }
- // Only integer and floating literals, otherwise try to rewrite to boxed
- // expression.
- if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- ASTContext &Ctx = NS.getASTContext();
- Selector Sel = Msg->getSelector();
- std::optional<NSAPI::NSNumberLiteralMethodKind> MKOpt =
- NS.getNSNumberLiteralMethodKind(Sel);
- if (!MKOpt)
- return false;
- NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
- bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
- bool CallIsFloating = false, CallIsDouble = false;
- switch (MK) {
- // We cannot have these calls with int/float literals.
- case NSAPI::NSNumberWithChar:
- case NSAPI::NSNumberWithUnsignedChar:
- case NSAPI::NSNumberWithShort:
- case NSAPI::NSNumberWithUnsignedShort:
- case NSAPI::NSNumberWithBool:
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- case NSAPI::NSNumberWithUnsignedInt:
- case NSAPI::NSNumberWithUnsignedInteger:
- CallIsUnsigned = true;
- [[fallthrough]];
- case NSAPI::NSNumberWithInt:
- case NSAPI::NSNumberWithInteger:
- break;
- case NSAPI::NSNumberWithUnsignedLong:
- CallIsUnsigned = true;
- [[fallthrough]];
- case NSAPI::NSNumberWithLong:
- CallIsLong = true;
- break;
- case NSAPI::NSNumberWithUnsignedLongLong:
- CallIsUnsigned = true;
- [[fallthrough]];
- case NSAPI::NSNumberWithLongLong:
- CallIsLongLong = true;
- break;
- case NSAPI::NSNumberWithDouble:
- CallIsDouble = true;
- [[fallthrough]];
- case NSAPI::NSNumberWithFloat:
- CallIsFloating = true;
- break;
- }
- SourceRange ArgRange = Arg->getSourceRange();
- QualType ArgTy = Arg->getType();
- QualType CallTy = Msg->getArg(0)->getType();
- // Check for the easy case, the literal maps directly to the call.
- if (Ctx.hasSameType(ArgTy, CallTy)) {
- commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
- commit.insert(ArgRange.getBegin(), "@");
- return true;
- }
- // We will need to modify the literal suffix to get the same type as the call.
- // Try with boxed expression if it came from a macro.
- if (ArgRange.getBegin().isMacroID())
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- bool LitIsFloat = ArgTy->isFloatingType();
- // For a float passed to integer call, don't try rewriting to objc literal.
- // It is difficult and a very uncommon case anyway.
- // But try with boxed expression.
- if (LitIsFloat && !CallIsFloating)
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- // Try to modify the literal make it the same type as the method call.
- // -Modify the suffix, and/or
- // -Change integer to float
- LiteralInfo LitInfo;
- bool isIntZero = false;
- if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
- isIntZero = !IntE->getValue().getBoolValue();
- if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- // Not easy to do int -> float with hex/octal and uncommon anyway.
- if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
- return rewriteToNumericBoxedExpression(Msg, NS, commit);
- SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
- SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
- commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
- LitInfo.WithoutSuffRange);
- commit.insert(LitB, "@");
- if (!LitIsFloat && CallIsFloating)
- commit.insert(LitE, ".0");
- if (CallIsFloating) {
- if (!CallIsDouble)
- commit.insert(LitE, LitInfo.F);
- } else {
- if (CallIsUnsigned)
- commit.insert(LitE, LitInfo.U);
- if (CallIsLong)
- commit.insert(LitE, LitInfo.L);
- else if (CallIsLongLong)
- commit.insert(LitE, LitInfo.LL);
- }
- return true;
- }
- // FIXME: Make determination of operator precedence more general and
- // make it broadly available.
- static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
- const Expr* Expr = FullExpr->IgnoreImpCasts();
- if (isa<ArraySubscriptExpr>(Expr) ||
- isa<CallExpr>(Expr) ||
- isa<DeclRefExpr>(Expr) ||
- isa<CXXNamedCastExpr>(Expr) ||
- isa<CXXConstructExpr>(Expr) ||
- isa<CXXThisExpr>(Expr) ||
- isa<CXXTypeidExpr>(Expr) ||
- isa<CXXUnresolvedConstructExpr>(Expr) ||
- isa<ObjCMessageExpr>(Expr) ||
- isa<ObjCPropertyRefExpr>(Expr) ||
- isa<ObjCProtocolExpr>(Expr) ||
- isa<MemberExpr>(Expr) ||
- isa<ObjCIvarRefExpr>(Expr) ||
- isa<ParenExpr>(FullExpr) ||
- isa<ParenListExpr>(Expr) ||
- isa<SizeOfPackExpr>(Expr))
- return false;
- return true;
- }
- static bool castOperatorNeedsParens(const Expr *FullExpr) {
- const Expr* Expr = FullExpr->IgnoreImpCasts();
- if (isa<ArraySubscriptExpr>(Expr) ||
- isa<CallExpr>(Expr) ||
- isa<DeclRefExpr>(Expr) ||
- isa<CastExpr>(Expr) ||
- isa<CXXNewExpr>(Expr) ||
- isa<CXXConstructExpr>(Expr) ||
- isa<CXXDeleteExpr>(Expr) ||
- isa<CXXNoexceptExpr>(Expr) ||
- isa<CXXPseudoDestructorExpr>(Expr) ||
- isa<CXXScalarValueInitExpr>(Expr) ||
- isa<CXXThisExpr>(Expr) ||
- isa<CXXTypeidExpr>(Expr) ||
- isa<CXXUnresolvedConstructExpr>(Expr) ||
- isa<ObjCMessageExpr>(Expr) ||
- isa<ObjCPropertyRefExpr>(Expr) ||
- isa<ObjCProtocolExpr>(Expr) ||
- isa<MemberExpr>(Expr) ||
- isa<ObjCIvarRefExpr>(Expr) ||
- isa<ParenExpr>(FullExpr) ||
- isa<ParenListExpr>(Expr) ||
- isa<SizeOfPackExpr>(Expr) ||
- isa<UnaryOperator>(Expr))
- return false;
- return true;
- }
- static void objectifyExpr(const Expr *E, Commit &commit) {
- if (!E) return;
- QualType T = E->getType();
- if (T->isObjCObjectPointerType()) {
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
- return;
- } else {
- return;
- }
- } else if (!T->isPointerType()) {
- return;
- }
- SourceRange Range = E->getSourceRange();
- if (castOperatorNeedsParens(E))
- commit.insertWrap("(", Range, ")");
- commit.insertBefore(Range.getBegin(), "(id)");
- }
- //===----------------------------------------------------------------------===//
- // rewriteToNumericBoxedExpression.
- //===----------------------------------------------------------------------===//
- static bool isEnumConstant(const Expr *E) {
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
- if (const ValueDecl *VD = DRE->getDecl())
- return isa<EnumConstantDecl>(VD);
- return false;
- }
- static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
- if (Msg->getNumArgs() != 1)
- return false;
- const Expr *Arg = Msg->getArg(0);
- if (Arg->isTypeDependent())
- return false;
- ASTContext &Ctx = NS.getASTContext();
- Selector Sel = Msg->getSelector();
- std::optional<NSAPI::NSNumberLiteralMethodKind> MKOpt =
- NS.getNSNumberLiteralMethodKind(Sel);
- if (!MKOpt)
- return false;
- NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
- const Expr *OrigArg = Arg->IgnoreImpCasts();
- QualType FinalTy = Arg->getType();
- QualType OrigTy = OrigArg->getType();
- uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
- uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
- bool isTruncated = FinalTySize < OrigTySize;
- bool needsCast = false;
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
- switch (ICE->getCastKind()) {
- case CK_LValueToRValue:
- case CK_NoOp:
- case CK_UserDefinedConversion:
- break;
- case CK_IntegralCast: {
- if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
- break;
- // Be more liberal with Integer/UnsignedInteger which are very commonly
- // used.
- if ((MK == NSAPI::NSNumberWithInteger ||
- MK == NSAPI::NSNumberWithUnsignedInteger) &&
- !isTruncated) {
- if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
- break;
- if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
- OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
- break;
- }
- needsCast = true;
- break;
- }
- case CK_PointerToBoolean:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_AtomicToNonAtomic:
- case CK_AddressSpaceConversion:
- needsCast = true;
- break;
- case CK_Dependent:
- case CK_BitCast:
- case CK_LValueBitCast:
- case CK_LValueToRValueBitCast:
- case CK_BaseToDerived:
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase:
- case CK_Dynamic:
- case CK_ToUnion:
- case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
- case CK_NullToPointer:
- case CK_NullToMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_MemberPointerToBoolean:
- case CK_ReinterpretMemberPointer:
- case CK_ConstructorConversion:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_ToVoid:
- case CK_VectorSplat:
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCObjectLValueCast:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_ARCProduceObject:
- case CK_ARCConsumeObject:
- case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject:
- case CK_NonAtomicToAtomic:
- case CK_CopyAndAutoreleaseBlockObject:
- case CK_BuiltinFnToFnPtr:
- case CK_ZeroToOCLOpaqueType:
- case CK_IntToOCLSampler:
- case CK_MatrixCast:
- return false;
- case CK_BooleanToSignedIntegral:
- llvm_unreachable("OpenCL-specific cast in Objective-C?");
- case CK_FloatingToFixedPoint:
- case CK_FixedPointToFloating:
- case CK_FixedPointCast:
- case CK_FixedPointToBoolean:
- case CK_FixedPointToIntegral:
- case CK_IntegralToFixedPoint:
- llvm_unreachable("Fixed point types are disabled for Objective-C");
- }
- }
- if (needsCast) {
- DiagnosticsEngine &Diags = Ctx.getDiagnostics();
- // FIXME: Use a custom category name to distinguish migration diagnostics.
- unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
- "converting to boxing syntax requires casting %0 to %1");
- Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
- << Msg->getSourceRange();
- return false;
- }
- SourceRange ArgRange = OrigArg->getSourceRange();
- commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
- if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
- commit.insertBefore(ArgRange.getBegin(), "@");
- else
- commit.insertWrap("@(", ArgRange, ")");
- return true;
- }
- //===----------------------------------------------------------------------===//
- // rewriteToStringBoxedExpression.
- //===----------------------------------------------------------------------===//
- static bool doRewriteToUTF8StringBoxedExpressionHelper(
- const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
- const Expr *Arg = Msg->getArg(0);
- if (Arg->isTypeDependent())
- return false;
- ASTContext &Ctx = NS.getASTContext();
- const Expr *OrigArg = Arg->IgnoreImpCasts();
- QualType OrigTy = OrigArg->getType();
- if (OrigTy->isArrayType())
- OrigTy = Ctx.getArrayDecayedType(OrigTy);
- if (const StringLiteral *
- StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
- commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
- commit.insert(StrE->getBeginLoc(), "@");
- return true;
- }
- if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
- QualType PointeeType = PT->getPointeeType();
- if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
- SourceRange ArgRange = OrigArg->getSourceRange();
- commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
- if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
- commit.insertBefore(ArgRange.getBegin(), "@");
- else
- commit.insertWrap("@(", ArgRange, ")");
- return true;
- }
- }
- return false;
- }
- static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
- Selector Sel = Msg->getSelector();
- if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
- Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString) ||
- Sel == NS.getNSStringSelector(NSAPI::NSStr_initWithUTF8String)) {
- if (Msg->getNumArgs() != 1)
- return false;
- return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
- }
- if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
- if (Msg->getNumArgs() != 2)
- return false;
- const Expr *encodingArg = Msg->getArg(1);
- if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
- NS.isNSASCIIStringEncodingConstant(encodingArg))
- return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
- }
- return false;
- }
|