Coverage Report

Created: 2022-01-18 06:27

/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
22
using namespace clang;
23
using namespace edit;
24
25
static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
26
                                    IdentifierInfo *&ClassId,
27
12.4k
                                    const LangOptions &LangOpts) {
28
12.4k
  if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
29
1.08k
    return false;
30
31
11.3k
  const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
32
11.3k
  if (!Receiver)
33
1.29k
    return false;
34
10.0k
  ClassId = Receiver->getIdentifier();
35
36
10.0k
  if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
37
3.78k
    return true;
38
39
  // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
40
  // since the change from +1 to +0 will be handled fine by ARC.
41
6.22k
  if (LangOpts.ObjCAutoRefCount) {
42
730
    if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
43
730
      if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
44
730
                           Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
45
154
        if (Rec->getMethodFamily() == OMF_alloc)
46
125
          return true;
47
154
      }
48
730
    }
49
730
  }
50
51
6.10k
  return false;
52
6.22k
}
53
54
//===----------------------------------------------------------------------===//
55
// rewriteObjCRedundantCallWithLiteral.
56
//===----------------------------------------------------------------------===//
57
58
bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
59
11.8k
                                              const NSAPI &NS, Commit &commit) {
60
11.8k
  IdentifierInfo *II = nullptr;
61
11.8k
  if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
62
8.44k
    return false;
63
3.39k
  if (Msg->getNumArgs() != 1)
64
2.67k
    return false;
65
66
712
  const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
67
712
  Selector Sel = Msg->getSelector();
68
69
712
  if ((isa<ObjCStringLiteral>(Arg) &&
70
712
       
NS.getNSClassId(NSAPI::ClassId_NSString) == II24
&&
71
712
       
(7
NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel7
||
72
7
        
NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel4
)) ||
73
74
712
      
(706
isa<ObjCArrayLiteral>(Arg)706
&&
75
706
       
NS.getNSClassId(NSAPI::ClassId_NSArray) == II6
&&
76
706
       
(3
NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel3
||
77
3
        
NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel0
)) ||
78
79
712
      
(703
isa<ObjCDictionaryLiteral>(Arg)703
&&
80
703
       
NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II3
&&
81
703
       
(3
NS.getNSDictionarySelector(
82
3
                              NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
83
12
        
NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel0
))) {
84
85
12
    commit.replaceWithInner(Msg->getSourceRange(),
86
12
                           Msg->getArg(0)->getSourceRange());
87
12
    return true;
88
12
  }
89
90
700
  return false;
91
712
}
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
113
  // If the receiver has type 'id'...
114
40
  if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
115
39
    return IFace;
116
117
1
  const ObjCMessageExpr *
118
1
    InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
119
1
  if (!InnerMsg)
120
0
    return IFace;
121
122
1
  QualType ClassRec;
123
1
  switch (InnerMsg->getReceiverKind()) {
124
0
  case ObjCMessageExpr::Instance:
125
0
  case ObjCMessageExpr::SuperInstance:
126
0
    return IFace;
127
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
136
1
  if (ClassRec.isNull())
137
0
    return IFace;
138
139
  // ...and it is the result of a class message...
140
141
1
  const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
142
1
  if (!ObjTy)
143
0
    return IFace;
144
1
  const ObjCInterfaceDecl *OID = ObjTy->getInterface();
145
146
  // ...and the receiving class is NSMapTable or NSLocale, return that
147
  // class as the receiving interface.
148
1
  if (OID->getName() == "NSMapTable" ||
149
1
      OID->getName() == "NSLocale")
150
1
    return OID;
151
152
0
  return IFace;
153
1
}
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
164
40
  if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
165
31
    if (!MD->isUnavailable())
166
29
      return true;
167
31
  }
168
11
  return false;
169
40
}
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
188
19
  SourceRange MsgRange = Msg->getSourceRange();
189
19
  SourceRange RecRange = Rec->getSourceRange();
190
19
  SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
191
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
11
}
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
14
}
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
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
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
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
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
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
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
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
304
48
  if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
305
11
    return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
306
307
37
  if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
308
14
    return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
309
310
23
  if (Msg->getNumArgs() != 2)
311
7
    return false;
312
313
16
  if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
314
6
    return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
315
316
10
  if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
317
9
    return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
318
319
1
  return false;
320
10
}
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
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
354
1
  return false;
355
13
}
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
24
  }
386
387
19
  Selector Sel = Msg->getSelector();
388
19
  SourceRange MsgRange = Msg->getSourceRange();
389
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
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
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
415
24
    
for (unsigned i = 0, e = Msg->getNumArgs() - 1; 8
i != e;
++i16
)
416
16
      objectifyExpr(Msg->getArg(i), commit);
417
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
429
2
  return false;
430
10
}
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
444
20
  E = E->IgnoreParenCasts();
445
20
  if (!E)
446
0
    return false;
447
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
453
16
    if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
454
0
      return false;
455
456
16
    Selector Sel = Msg->getSelector();
457
16
    if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
458
0
      return true; // empty array.
459
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
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
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
480
16
  } else 
if (const ObjCArrayLiteral *4
ArrLit4
= 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
486
2
  return false;
487
20
}
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
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
501
19
  if (Sel == NS.getNSDictionarySelector(
502
19
                                    NSAPI::NSDict_dictionaryWithObjectForKey)) {
503
5
    if (Msg->getNumArgs() != 2)
504
0
      return false;
505
506
5
    objectifyExpr(Msg->getArg(0), commit);
507
5
    objectifyExpr(Msg->getArg(1), commit);
508
509
5
    SourceRange ValRange = Msg->getArg(0)->getSourceRange();
510
5
    SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
511
    // 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
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
532
8
    if (Msg->getNumArgs() == 1) {
533
0
      commit.replace(MsgRange, "@{}");
534
0
      return true;
535
0
    }
536
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
541
14
      SourceRange ValRange = Msg->getArg(i)->getSourceRange();
542
14
      SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
543
      // 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
    // Range of arguments up until and including the last key.
550
    // The sentinel and first value are cut off, the value will move after the
551
    // 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
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
565
4
    SmallVector<const Expr *, 8> Vals;
566
4
    if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
567
0
      return false;
568
569
4
    SmallVector<const Expr *, 8> Keys;
570
4
    if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
571
1
      return false;
572
573
3
    if (Vals.size() != Keys.size())
574
0
      return false;
575
576
3
    if (Vals.empty()) {
577
0
      commit.replace(MsgRange, "@{}");
578
0
      return true;
579
0
    }
580
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
585
6
      SourceRange ValRange = Vals[i]->getSourceRange();
586
6
      SourceRange KeyRange = Keys[i]->getSourceRange();
587
      // Insert value after key.
588
6
      commit.insertAfterToken(KeyRange.getEnd(), ": ");
589
6
      commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
590
6
    }
591
    // Range of arguments up until and including the last key.
592
    // 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
599
2
  return false;
600
6
}
601
602
static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
603
24
                                                 const NSAPI &NS) {
604
24
  if (!Msg)
605
12
    return false;
606
607
12
  IdentifierInfo *II = nullptr;
608
12
  if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
609
1
    return false;
610
611
11
  if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
612
3
    return false;
613
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
621
6
    SmallVector<const Expr *, 8> Vals;
622
6
    if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
623
0
      return false;
624
625
6
    SmallVector<const Expr *, 8> Keys;
626
6
    if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
627
1
      return false;
628
629
5
    if (Vals.size() != Keys.size())
630
0
      return false;
631
632
5
    return true;
633
5
  }
634
635
2
  return false;
636
8
}
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
655
15
  return rewriteToNumericBoxedExpression(Msg, NS, commit);
656
17
}
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
669
56
  return rewriteToNumericBoxedExpression(Msg, NS, commit);
670
60
}
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
694
130
  Optional<bool> UpperU, UpperL;
695
130
  bool UpperF = false;
696
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.17k
    }
705
130
  };
706
707
256
  while (true) {
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
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
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
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
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
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
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
771
  // Only integer and floating literals, otherwise try to rewrite to boxed
772
  // expression.
773
342
  if (!isa<IntegerLiteral>(literalE) && 
!isa<FloatingLiteral>(literalE)95
)
774
5
    return rewriteToNumericBoxedExpression(Msg, NS, commit);
775
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
784
337
  bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
785
337
  bool CallIsFloating = false, CallIsDouble = false;
786
787
337
  switch (MK) {
788
  // We cannot have these calls with int/float literals.
789
22
  case NSAPI::NSNumberWithChar:
790
44
  case NSAPI::NSNumberWithUnsignedChar:
791
66
  case NSAPI::NSNumberWithShort:
792
88
  case NSAPI::NSNumberWithUnsignedShort:
793
110
  case NSAPI::NSNumberWithBool:
794
110
    return rewriteToNumericBoxedExpression(Msg, NS, commit);
795
796
22
  case NSAPI::NSNumberWithUnsignedInt:
797
44
  case NSAPI::NSNumberWithUnsignedInteger:
798
44
    CallIsUnsigned = true;
799
44
    LLVM_FALLTHROUGH;
800
73
  case NSAPI::NSNumberWithInt:
801
95
  case NSAPI::NSNumberWithInteger:
802
95
    break;
803
804
22
  case NSAPI::NSNumberWithUnsignedLong:
805
22
    CallIsUnsigned = true;
806
22
    LLVM_FALLTHROUGH;
807
44
  case NSAPI::NSNumberWithLong:
808
44
    CallIsLong = true;
809
44
    break;
810
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
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
337
  }
825
826
227
  SourceRange ArgRange = Arg->getSourceRange();
827
227
  QualType ArgTy = Arg->getType();
828
227
  QualType CallTy = Msg->getArg(0)->getType();
829
830
  // 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
837
  // We will need to modify the literal suffix to get the same type as the call.
838
  // Try with boxed expression if it came from a macro.
839
196
  if (ArgRange.getBegin().isMacroID())
840
18
    return rewriteToNumericBoxedExpression(Msg, NS, commit);
841
842
178
  bool LitIsFloat = ArgTy->isFloatingType();
843
  // For a float passed to integer call, don't try rewriting to objc literal.
844
  // It is difficult and a very uncommon case anyway.
845
  // But try with boxed expression.
846
178
  if (LitIsFloat && 
!CallIsFloating56
)
847
48
    return rewriteToNumericBoxedExpression(Msg, NS, commit);
848
849
  // Try to modify the literal make it the same type as the method call.
850
  // -Modify the suffix, and/or
851
  // -Change integer to float
852
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
860
  // 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
864
126
  SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
865
126
  SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
866
867
126
  commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
868
126
                         LitInfo.WithoutSuffRange);
869
126
  commit.insert(LitB, "@");
870
871
126
  if (!LitIsFloat && 
CallIsFloating118
)
872
24
    commit.insert(LitE, ".0");
873
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
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
130
}
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
911
2
  return true;
912
29
}
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
939
0
  return true;
940
9
}
941
942
70
static void objectifyExpr(const Expr *E, Commit &commit) {
943
70
  if (!E) 
return0
;
944
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
41
    } else {
951
26
      return;
952
26
    }
953
67
  } else 
if (3
!T->isPointerType()3
) {
954
0
    return;
955
0
  }
956
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
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
980
256
  const Expr *Arg = Msg->getArg(0);
981
256
  if (Arg->isTypeDependent())
982
0
    return false;
983
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
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
998
256
  bool isTruncated = FinalTySize < OrigTySize;
999
256
  bool needsCast = false;
1000
1001
256
  if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
1002
255
    switch (ICE->getCastKind()) {
1003
0
    case CK_LValueToRValue:
1004
0
    case CK_NoOp:
1005
0
    case CK_UserDefinedConversion:
1006
0
      break;
1007
1008
158
    case CK_IntegralCast: {
1009
158
      if (MK == NSAPI::NSNumberWithBool && 
OrigTy->isBooleanType()18
)
1010
1
        break;
1011
      // Be more liberal with Integer/UnsignedInteger which are very commonly
1012
      // 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
14
      }
1022
1023
153
      needsCast = true;
1024
153
      break;
1025
157
    }
1026
1027
0
    case CK_PointerToBoolean:
1028
0
    case CK_IntegralToBoolean:
1029
19
    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
1042
0
    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
    case CK_MatrixCast:
1084
0
      return false;
1085
1086
0
    case CK_BooleanToSignedIntegral:
1087
0
      llvm_unreachable("OpenCL-specific cast in Objective-C?");
1088
1089
0
    case CK_FloatingToFixedPoint:
1090
0
    case CK_FixedPointToFloating:
1091
0
    case CK_FixedPointCast:
1092
0
    case CK_FixedPointToBoolean:
1093
0
    case CK_FixedPointToIntegral:
1094
0
    case CK_IntegralToFixedPoint:
1095
0
      llvm_unreachable("Fixed point types are disabled for Objective-C");
1096
255
    }
1097
255
  }
1098
1099
256
  if (needsCast) {
1100
250
    DiagnosticsEngine &Diags = Ctx.getDiagnostics();
1101
    // FIXME: Use a custom category name to distinguish migration diagnostics.
1102
250
    unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
1103
250
                       "converting to boxing syntax requires casting %0 to %1");
1104
250
    Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
1105
250
        << Msg->getSourceRange();
1106
250
    return false;
1107
250
  }
1108
1109
6
  SourceRange ArgRange = OrigArg->getSourceRange();
1110
6
  commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1111
1112
6
  if (isa<ParenExpr>(OrigArg) || 
isa<IntegerLiteral>(OrigArg)5
)
1113
3
    commit.insertBefore(ArgRange.getBegin(), "@");
1114
3
  else
1115
3
    commit.insertWrap("@(", ArgRange, ")");
1116
1117
6
  return true;
1118
256
}
1119
1120
//===----------------------------------------------------------------------===//
1121
// rewriteToStringBoxedExpression.
1122
//===----------------------------------------------------------------------===//
1123
1124
static bool doRewriteToUTF8StringBoxedExpressionHelper(
1125
                                              const ObjCMessageExpr *Msg,
1126
9
                                              const NSAPI &NS, Commit &commit) {
1127
9
  const Expr *Arg = Msg->getArg(0);
1128
9
  if (Arg->isTypeDependent())
1129
0
    return false;
1130
1131
9
  ASTContext &Ctx = NS.getASTContext();
1132
1133
9
  const Expr *OrigArg = Arg->IgnoreImpCasts();
1134
9
  QualType OrigTy = OrigArg->getType();
1135
9
  if (OrigTy->isArrayType())
1136
2
    OrigTy = Ctx.getArrayDecayedType(OrigTy);
1137
1138
9
  if (const StringLiteral *
1139
9
        StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
1140
1
    commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
1141
1
    commit.insert(StrE->getBeginLoc(), "@");
1142
1
    return true;
1143
1
  }
1144
1145
8
  if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
1146
8
    QualType PointeeType = PT->getPointeeType();
1147
8
    if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
1148
8
      SourceRange ArgRange = OrigArg->getSourceRange();
1149
8
      commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1150
1151
8
      if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1152
0
        commit.insertBefore(ArgRange.getBegin(), "@");
1153
8
      else
1154
8
        commit.insertWrap("@(", ArgRange, ")");
1155
1156
8
      return true;
1157
8
    }
1158
8
  }
1159
1160
0
  return false;
1161
8
}
1162
1163
static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
1164
12
                                           const NSAPI &NS, Commit &commit) {
1165
12
  Selector Sel = Msg->getSelector();
1166
1167
12
  if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
1168
12
      
Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)7
||
1169
12
      
Sel == NS.getNSStringSelector(NSAPI::NSStr_initWithUTF8String)6
) {
1170
7
    if (Msg->getNumArgs() != 1)
1171
0
      return false;
1172
7
    return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1173
7
  }
1174
1175
5
  if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
1176
4
    if (Msg->getNumArgs() != 2)
1177
0
      return false;
1178
1179
4
    const Expr *encodingArg = Msg->getArg(1);
1180
4
    if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
1181
4
        
NS.isNSASCIIStringEncodingConstant(encodingArg)3
)
1182
2
      return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1183
4
  }
1184
1185
3
  return false;
1186
5
}