Coverage Report

Created: 2019-07-24 05:18

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