Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
// rewriteUnbridgedCasts:
11
//
12
// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
13
// is from a file-level variable, __bridge cast is used to convert it.
14
// For the result of a function call that we know is +1/+0,
15
// __bridge/CFBridgingRelease is used.
16
//
17
//  NSString *str = (NSString *)kUTTypePlainText;
18
//  str = b ? kUTTypeRTF : kUTTypePlainText;
19
//  NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
20
//                                                         _uuid);
21
// ---->
22
//  NSString *str = (__bridge NSString *)kUTTypePlainText;
23
//  str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
24
// NSString *_uuidString = (NSString *)
25
//            CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
26
//
27
// For a C pointer to ObjC, for casting 'self', __bridge is used.
28
//
29
//  CFStringRef str = (CFStringRef)self;
30
// ---->
31
//  CFStringRef str = (__bridge CFStringRef)self;
32
//
33
// Uses of Block_copy/Block_release macros are rewritten:
34
//
35
//  c = Block_copy(b);
36
//  Block_release(c);
37
// ---->
38
//  c = [b copy];
39
//  <removed>
40
//
41
//===----------------------------------------------------------------------===//
42
43
#include "Transforms.h"
44
#include "Internals.h"
45
#include "clang/AST/ASTContext.h"
46
#include "clang/AST/Attr.h"
47
#include "clang/AST/ParentMap.h"
48
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
49
#include "clang/Basic/SourceManager.h"
50
#include "clang/Lex/Lexer.h"
51
#include "clang/Sema/SemaDiagnostic.h"
52
#include "llvm/ADT/SmallString.h"
53
54
using namespace clang;
55
using namespace arcmt;
56
using namespace trans;
57
58
namespace {
59
60
class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
61
  MigrationPass &Pass;
62
  IdentifierInfo *SelfII;
63
  std::unique_ptr<ParentMap> StmtMap;
64
  Decl *ParentD;
65
  Stmt *Body;
66
  mutable std::unique_ptr<ExprSet> Removables;
67
68
public:
69
  UnbridgedCastRewriter(MigrationPass &pass)
70
425
    : Pass(pass), ParentD(nullptr), Body(nullptr) {
71
425
    SelfII = &Pass.Ctx.Idents.get("self");
72
425
  }
73
74
425
  void transformBody(Stmt *body, Decl *ParentD) {
75
425
    this->ParentD = ParentD;
76
425
    Body = body;
77
425
    StmtMap.reset(new ParentMap(body));
78
425
    TraverseStmt(body);
79
425
  }
80
81
22
  bool TraverseBlockDecl(BlockDecl *D) {
82
22
    // ParentMap does not enter into a BlockDecl to record its stmts, so use a
83
22
    // new UnbridgedCastRewriter to handle the block.
84
22
    UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D);
85
22
    return true;
86
22
  }
87
88
1.87k
  bool VisitCastExpr(CastExpr *E) {
89
1.87k
    if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
90
1.79k
        E->getCastKind() != CK_BitCast &&
91
1.57k
        E->getCastKind() != CK_AnyPointerToBlockPointerCast)
92
1.56k
      return true;
93
308
94
308
    QualType castType = E->getType();
95
308
    Expr *castExpr = E->getSubExpr();
96
308
    QualType castExprType = castExpr->getType();
97
308
98
308
    if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
99
128
      return true;
100
180
    
101
180
    bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
102
180
    bool castRetainable = castType->isObjCIndirectLifetimeType();
103
180
    if (
exprRetainable == castRetainable180
)
return true2
;
104
178
105
178
    
if (178
castExpr->isNullPointerConstant(Pass.Ctx,
106
178
                                        Expr::NPC_ValueDependentIsNull))
107
0
      return true;
108
178
109
178
    SourceLocation loc = castExpr->getExprLoc();
110
178
    if (
loc.isValid() && 178
Pass.Ctx.getSourceManager().isInSystemHeader(loc)178
)
111
0
      return true;
112
178
113
178
    
if (178
castType->isObjCRetainableType()178
)
114
85
      transformNonObjCToObjCCast(E);
115
178
    else
116
93
      transformObjCToNonObjCCast(E);
117
1.87k
118
1.87k
    return true;
119
1.87k
  }
120
121
private:
122
85
  void transformNonObjCToObjCCast(CastExpr *E) {
123
85
    if (
!E85
)
return0
;
124
85
125
85
    // Global vars are assumed that are cast as unretained.
126
85
    
if (85
isGlobalVar(E)85
)
127
14
      
if (14
E->getSubExpr()->getType()->isPointerType()14
) {
128
14
        castToObjCObject(E, /*retained=*/false);
129
14
        return;
130
14
      }
131
71
132
71
    // If the cast is directly over the result of a Core Foundation function
133
71
    // try to figure out whether it should be cast as retained or unretained.
134
71
    Expr *inner = E->IgnoreParenCasts();
135
71
    if (CallExpr *
callE71
= dyn_cast<CallExpr>(inner)) {
136
17
      if (FunctionDecl *
FD17
= callE->getDirectCallee()) {
137
17
        if (
FD->hasAttr<CFReturnsRetainedAttr>()17
) {
138
0
          castToObjCObject(E, /*retained=*/true);
139
0
          return;
140
0
        }
141
17
        
if (17
FD->hasAttr<CFReturnsNotRetainedAttr>()17
) {
142
0
          castToObjCObject(E, /*retained=*/false);
143
0
          return;
144
0
        }
145
17
        
if (17
FD->isGlobal() &&
146
17
            FD->getIdentifier() &&
147
17
            ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
148
17
                                   FD->getIdentifier()->getName())) {
149
13
          StringRef fname = FD->getIdentifier()->getName();
150
13
          if (fname.endswith("Retain") ||
151
4
              fname.find("Create") != StringRef::npos ||
152
13
              
fname.find("Copy") != StringRef::npos0
) {
153
13
            // Do not migrate to couple of bridge transfer casts which
154
13
            // cancel each other out. Leave it unchanged so error gets user
155
13
            // attention instead.
156
13
            if (FD->getName() == "CFRetain" && 
157
9
                FD->getNumParams() == 1 &&
158
9
                FD->getParent()->isTranslationUnit() &&
159
13
                
FD->isExternallyVisible()9
) {
160
9
              Expr *Arg = callE->getArg(0);
161
9
              if (const ImplicitCastExpr *
ICE9
= dyn_cast<ImplicitCastExpr>(Arg)) {
162
8
                const Expr *sub = ICE->getSubExpr();
163
8
                QualType T = sub->getType();
164
8
                if (T->isObjCObjectPointerType())
165
3
                  return;
166
10
              }
167
9
            }
168
10
            castToObjCObject(E, /*retained=*/true);
169
10
            return;
170
10
          }
171
0
172
0
          
if (0
fname.find("Get") != StringRef::npos0
) {
173
0
            castToObjCObject(E, /*retained=*/false);
174
0
            return;
175
0
          }
176
58
        }
177
17
      }
178
17
    }
179
58
180
58
    // If returning an ivar or a member of an ivar from a +0 method, use
181
58
    // a __bridge cast.
182
58
    Expr *base = inner->IgnoreParenImpCasts();
183
61
    while (isa<MemberExpr>(base))
184
3
      base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
185
58
    if (isa<ObjCIvarRefExpr>(base) &&
186
58
        
isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))9
) {
187
7
      if (ObjCMethodDecl *
method7
= dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
188
7
        if (
!method->hasAttr<NSReturnsRetainedAttr>()7
) {
189
6
          castToObjCObject(E, /*retained=*/false);
190
6
          return;
191
6
        }
192
52
      }
193
7
    }
194
85
  }
195
196
30
  void castToObjCObject(CastExpr *E, bool retained) {
197
30
    rewriteToBridgedCast(E, retained ? 
OBC_BridgeTransfer10
:
OBC_Bridge20
);
198
30
  }
199
200
57
  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
201
57
    Transaction Trans(Pass.TA);
202
57
    rewriteToBridgedCast(E, Kind, Trans);
203
57
  }
204
205
  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
206
67
                            Transaction &Trans) {
207
67
    TransformActions &TA = Pass.TA;
208
67
209
67
    // We will remove the compiler diagnostic.
210
67
    if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
211
67
                          diag::err_arc_cast_requires_bridge,
212
67
                          E->getLocStart())) {
213
8
      Trans.abort();
214
8
      return;
215
8
    }
216
59
217
59
    StringRef bridge;
218
59
    switch(Kind) {
219
23
    case OBC_Bridge:
220
23
      bridge = "__bridge "; break;
221
10
    case OBC_BridgeTransfer:
222
10
      bridge = "__bridge_transfer "; break;
223
26
    case OBC_BridgeRetained:
224
26
      bridge = "__bridge_retained "; break;
225
59
    }
226
59
227
59
    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
228
59
                       diag::err_arc_cast_requires_bridge,
229
59
                       E->getLocStart());
230
59
    if (
Kind == OBC_Bridge || 59
!Pass.CFBridgingFunctionsDefined()36
) {
231
23
      if (CStyleCastExpr *
CCE23
= dyn_cast<CStyleCastExpr>(E)) {
232
9
        TA.insertAfterToken(CCE->getLParenLoc(), bridge);
233
23
      } else {
234
14
        SourceLocation insertLoc = E->getSubExpr()->getLocStart();
235
14
        SmallString<128> newCast;
236
14
        newCast += '(';
237
14
        newCast += bridge;
238
14
        newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
239
14
        newCast += ')';
240
14
241
14
        if (
isa<ParenExpr>(E->getSubExpr())14
) {
242
0
          TA.insert(insertLoc, newCast.str());
243
14
        } else {
244
14
          newCast += '(';
245
14
          TA.insert(insertLoc, newCast.str());
246
14
          TA.insertAfterToken(E->getLocEnd(), ")");
247
14
        }
248
14
      }
249
59
    } else {
250
36
      assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
251
36
      SmallString<32> BridgeCall;
252
36
253
36
      Expr *WrapE = E->getSubExpr();
254
36
      SourceLocation InsertLoc = WrapE->getLocStart();
255
36
256
36
      SourceManager &SM = Pass.Ctx.getSourceManager();
257
36
      char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
258
36
      if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
259
0
        BridgeCall += ' ';
260
36
261
36
      if (Kind == OBC_BridgeTransfer)
262
10
        BridgeCall += "CFBridgingRelease";
263
36
      else
264
26
        BridgeCall += "CFBridgingRetain";
265
36
266
36
      if (
isa<ParenExpr>(WrapE)36
) {
267
0
        TA.insert(InsertLoc, BridgeCall);
268
36
      } else {
269
36
        BridgeCall += '(';
270
36
        TA.insert(InsertLoc, BridgeCall);
271
36
        TA.insertAfterToken(WrapE->getLocEnd(), ")");
272
36
      }
273
36
    }
274
67
  }
275
276
10
  void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
277
10
    Transaction Trans(Pass.TA);
278
10
    Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
279
10
    rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
280
10
  }
281
282
8
  void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
283
8
    SourceManager &SM = Pass.Ctx.getSourceManager();
284
8
    SourceLocation Loc = E->getExprLoc();
285
8
    assert(Loc.isMacroID());
286
8
    SourceLocation MacroBegin, MacroEnd;
287
8
    std::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
288
8
    SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
289
8
    SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
290
8
    SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
291
8
292
8
    Outer = SourceRange(MacroBegin, MacroEnd);
293
8
    Inner = SourceRange(InnerBegin, InnerEnd);
294
8
  }
295
296
4
  void rewriteBlockCopyMacro(CastExpr *E) {
297
4
    SourceRange OuterRange, InnerRange;
298
4
    getBlockMacroRanges(E, OuterRange, InnerRange);
299
4
300
4
    Transaction Trans(Pass.TA);
301
4
    Pass.TA.replace(OuterRange, InnerRange);
302
4
    Pass.TA.insert(InnerRange.getBegin(), "[");
303
4
    Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
304
4
    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
305
4
                            diag::err_arc_cast_requires_bridge,
306
4
                            OuterRange);
307
4
  }
308
309
4
  void removeBlockReleaseMacro(CastExpr *E) {
310
4
    SourceRange OuterRange, InnerRange;
311
4
    getBlockMacroRanges(E, OuterRange, InnerRange);
312
4
313
4
    Transaction Trans(Pass.TA);
314
4
    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
315
4
                            diag::err_arc_cast_requires_bridge,
316
4
                            OuterRange);
317
4
    if (
!hasSideEffects(E, Pass.Ctx)4
) {
318
4
      if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
319
4
        return;
320
0
    }
321
0
    Pass.TA.replace(OuterRange, InnerRange);
322
0
  }
323
324
4
  bool tryRemoving(Expr *E) const {
325
4
    if (
!Removables4
) {
326
4
      Removables.reset(new ExprSet);
327
4
      collectRemovables(Body, *Removables);
328
4
    }
329
4
330
4
    if (
Removables->count(E)4
) {
331
4
      Pass.TA.removeStmt(E);
332
4
      return true;
333
4
    }
334
0
335
0
    return false;
336
0
  }
337
338
93
  void transformObjCToNonObjCCast(CastExpr *E) {
339
93
    SourceLocation CastLoc = E->getExprLoc();
340
93
    if (
CastLoc.isMacroID()93
) {
341
8
      StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
342
8
                                                    Pass.Ctx.getSourceManager(),
343
8
                                                    Pass.Ctx.getLangOpts());
344
8
      if (
MacroName == "Block_copy"8
) {
345
4
        rewriteBlockCopyMacro(E);
346
4
        return;
347
4
      }
348
4
      
if (4
MacroName == "Block_release"4
) {
349
4
        removeBlockReleaseMacro(E);
350
4
        return;
351
4
      }
352
85
    }
353
85
354
85
    
if (85
isSelf(E->getSubExpr())85
)
355
4
      return rewriteToBridgedCast(E, OBC_Bridge);
356
81
357
81
    CallExpr *callE;
358
81
    if (isPassedToCFRetain(E, callE))
359
10
      return rewriteCastForCFRetain(E, callE);
360
71
361
71
    ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
362
71
    if (family == OMF_retain)
363
4
      return rewriteToBridgedCast(E, OBC_BridgeRetained);
364
67
365
67
    
if (67
family == OMF_autorelease || 67
family == OMF_release66
) {
366
1
      std::string err = "it is not safe to cast to '";
367
1
      err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
368
1
      err += "' the result of '";
369
1
      err += family == OMF_autorelease ? 
"autorelease"1
:
"release"0
;
370
1
      err += "' message; a __bridge cast may result in a pointer to a "
371
1
          "destroyed object and a __bridge_retained may leak the object";
372
1
      Pass.TA.reportError(err, E->getLocStart(),
373
1
                          E->getSubExpr()->getSourceRange());
374
1
      Stmt *parent = E;
375
2
      do {
376
2
        parent = StmtMap->getParentIgnoreParenImpCasts(parent);
377
2
      } while (
parent && 2
isa<ExprWithCleanups>(parent)2
);
378
1
379
1
      if (ReturnStmt *
retS1
= dyn_cast_or_null<ReturnStmt>(parent)) {
380
1
        std::string note = "remove the cast and change return type of function "
381
1
            "to '";
382
1
        note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
383
1
        note += "' to have the object automatically autoreleased";
384
1
        Pass.TA.reportNote(note, retS->getLocStart());
385
1
      }
386
1
    }
387
67
388
67
    Expr *subExpr = E->getSubExpr();
389
67
390
67
    // Look through pseudo-object expressions.
391
67
    if (PseudoObjectExpr *
pseudo67
= dyn_cast<PseudoObjectExpr>(subExpr)) {
392
2
      subExpr = pseudo->getResultExpr();
393
2
      assert(subExpr && "no result for pseudo-object of non-void type?");
394
2
    }
395
67
396
67
    if (ImplicitCastExpr *
implCE67
= dyn_cast<ImplicitCastExpr>(subExpr)) {
397
67
      if (implCE->getCastKind() == CK_ARCConsumeObject)
398
8
        return rewriteToBridgedCast(E, OBC_BridgeRetained);
399
59
      
if (59
implCE->getCastKind() == CK_ARCReclaimReturnedObject59
)
400
7
        return rewriteToBridgedCast(E, OBC_Bridge);
401
52
    }
402
52
403
52
    bool isConsumed = false;
404
52
    if (isPassedToCParamWithKnownOwnership(E, isConsumed))
405
4
      
return rewriteToBridgedCast(E, isConsumed ? 4
OBC_BridgeRetained4
406
4
                                                : OBC_Bridge);
407
48
  }
408
409
71
  static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
410
71
    E = E->IgnoreParenCasts();
411
71
    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
412
17
      return ME->getMethodFamily();
413
54
414
54
    return OMF_None;
415
54
  }
416
417
81
  bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
418
81
    if ((callE = dyn_cast_or_null<CallExpr>(
419
81
                                     StmtMap->getParentIgnoreParenImpCasts(E))))
420
16
      if (FunctionDecl *
421
16
            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
422
16
        
if (16
FD->getName() == "CFRetain" && 16
FD->getNumParams() == 110
&&
423
10
            FD->getParent()->isTranslationUnit() &&
424
10
            FD->isExternallyVisible())
425
10
          return true;
426
71
427
71
    return false;
428
71
  }
429
430
52
  bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
431
52
    if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
432
52
                                     StmtMap->getParentIgnoreParenImpCasts(E)))
433
6
      if (FunctionDecl *
434
6
            
FD6
= dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
435
6
        unsigned i = 0;
436
7
        for (unsigned e = callE->getNumArgs(); 
i != e7
;
++i1
) {
437
7
          Expr *arg = callE->getArg(i);
438
7
          if (
arg == E || 7
arg->IgnoreParenImpCasts() == E2
)
439
6
            break;
440
7
        }
441
6
        if (
i < callE->getNumArgs() && 6
i < FD->getNumParams()6
) {
442
5
          ParmVarDecl *PD = FD->getParamDecl(i);
443
5
          if (
PD->hasAttr<CFConsumedAttr>()5
) {
444
4
            isConsumed = true;
445
4
            return true;
446
4
          }
447
48
        }
448
6
      }
449
48
450
48
    return false;
451
48
  }
452
453
85
  bool isSelf(Expr *E) const {
454
85
    E = E->IgnoreParenLValueCasts();
455
85
    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
456
16
      
if (ImplicitParamDecl *16
IPD16
= dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
457
4
        
if (4
IPD->getIdentifier() == SelfII4
)
458
4
          return true;
459
81
460
81
    return false;
461
81
  }
462
};
463
464
} // end anonymous namespace
465
466
85
void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
467
85
  BodyTransform<UnbridgedCastRewriter> trans(pass);
468
85
  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
469
85
}