Coverage Report

Created: 2023-09-30 09:22

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