Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===//
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
// removeRetainReleaseDealloc:
10
//
11
// Removes retain/release/autorelease/dealloc messages.
12
//
13
//  return [[foo retain] autorelease];
14
// ---->
15
//  return foo;
16
//
17
//===----------------------------------------------------------------------===//
18
19
#include "Transforms.h"
20
#include "Internals.h"
21
#include "clang/AST/ASTContext.h"
22
#include "clang/AST/ParentMap.h"
23
#include "clang/Basic/SourceManager.h"
24
#include "clang/Lex/Lexer.h"
25
#include "clang/Sema/SemaDiagnostic.h"
26
#include "llvm/ADT/StringSwitch.h"
27
28
using namespace clang;
29
using namespace arcmt;
30
using namespace trans;
31
32
namespace {
33
34
class RetainReleaseDeallocRemover :
35
                       public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
36
  Stmt *Body;
37
  MigrationPass &Pass;
38
39
  ExprSet Removables;
40
  std::unique_ptr<ParentMap> StmtMap;
41
42
  Selector DelegateSel, FinalizeSel;
43
44
public:
45
  RetainReleaseDeallocRemover(MigrationPass &pass)
46
403
    : Body(nullptr), Pass(pass) {
47
403
    DelegateSel =
48
403
        Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
49
403
    FinalizeSel =
50
403
        Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
51
403
  }
52
53
403
  void transformBody(Stmt *body, Decl *ParentD) {
54
403
    Body = body;
55
403
    collectRemovables(body, Removables);
56
403
    StmtMap.reset(new ParentMap(body));
57
403
    TraverseStmt(body);
58
403
  }
59
60
495
  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
61
495
    switch (E->getMethodFamily()) {
62
495
    default:
63
270
      if (E->isInstanceMessage() && 
E->getSelector() == FinalizeSel192
)
64
0
        break;
65
270
      return true;
66
270
    case OMF_autorelease:
67
25
      if (isRemovable(E)) {
68
14
        if (!isCommonUnusedAutorelease(E)) {
69
2
          // An unused autorelease is badness. If we remove it the receiver
70
2
          // will likely die immediately while previously it was kept alive
71
2
          // by the autorelease pool. This is bad practice in general, leave it
72
2
          // and emit an error to force the user to restructure their code.
73
2
          Pass.TA.reportError(
74
2
              "it is not safe to remove an unused 'autorelease' "
75
2
              "message; its receiver may be destroyed immediately",
76
2
              E->getBeginLoc(), E->getSourceRange());
77
2
          return true;
78
2
        }
79
23
      }
80
23
      // Pass through.
81
23
      LLVM_FALLTHROUGH;
82
216
    case OMF_retain:
83
216
    case OMF_release:
84
216
      if (E->getReceiverKind() == ObjCMessageExpr::Instance)
85
216
        if (Expr *rec = E->getInstanceReceiver()) {
86
216
          rec = rec->IgnoreParenImpCasts();
87
216
          if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
88
216
              
(4
E->getMethodFamily() != OMF_retain4
||
isRemovable(E)4
)) {
89
2
            std::string err = "it is not safe to remove '";
90
2
            err += E->getSelector().getAsString() + "' message on "
91
2
                "an __unsafe_unretained type";
92
2
            Pass.TA.reportError(err, rec->getBeginLoc());
93
2
            return true;
94
2
          }
95
214
96
214
          if (isGlobalVar(rec) &&
97
214
              
(3
E->getMethodFamily() != OMF_retain3
||
isRemovable(E)2
)) {
98
3
            std::string err = "it is not safe to remove '";
99
3
            err += E->getSelector().getAsString() + "' message on "
100
3
                "a global variable";
101
3
            Pass.TA.reportError(err, rec->getBeginLoc());
102
3
            return true;
103
3
          }
104
211
105
211
          if (E->getMethodFamily() == OMF_release && 
isDelegateMessage(rec)117
) {
106
2
            Pass.TA.reportError(
107
2
                "it is not safe to remove 'retain' "
108
2
                "message on the result of a 'delegate' message; "
109
2
                "the object that was passed to 'setDelegate:' may not be "
110
2
                "properly retained",
111
2
                rec->getBeginLoc());
112
2
            return true;
113
2
          }
114
209
        }
115
209
      break;
116
209
    case OMF_dealloc:
117
7
      break;
118
216
    }
119
216
120
216
    switch (E->getReceiverKind()) {
121
216
    default:
122
0
      return true;
123
216
    case ObjCMessageExpr::SuperInstance: {
124
4
      Transaction Trans(Pass.TA);
125
4
      clearDiagnostics(E->getSelectorLoc(0));
126
4
      if (tryRemoving(E))
127
4
        return true;
128
0
      Pass.TA.replace(E->getSourceRange(), "self");
129
0
      return true;
130
0
    }
131
212
    case ObjCMessageExpr::Instance:
132
212
      break;
133
212
    }
134
212
135
212
    Expr *rec = E->getInstanceReceiver();
136
212
    if (!rec) 
return true0
;
137
212
138
212
    Transaction Trans(Pass.TA);
139
212
    clearDiagnostics(E->getSelectorLoc(0));
140
212
141
212
    ObjCMessageExpr *Msg = E;
142
212
    Expr *RecContainer = Msg;
143
212
    SourceRange RecRange = rec->getSourceRange();
144
212
    checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
145
212
146
212
    if (Msg->getMethodFamily() == OMF_release &&
147
212
        
isRemovable(RecContainer)115
&&
isInAtFinally(RecContainer)107
) {
148
2
      // Change the -release to "receiver = nil" in a finally to avoid a leak
149
2
      // when an exception is thrown.
150
2
      Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
151
2
      std::string str = " = ";
152
2
      str += getNilString(Pass);
153
2
      Pass.TA.insertAfterToken(RecRange.getEnd(), str);
154
2
      return true;
155
2
    }
156
210
157
210
    if (hasSideEffects(rec, Pass.Ctx) || 
!tryRemoving(RecContainer)179
)
158
75
      Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
159
210
160
210
    return true;
161
210
  }
162
163
private:
164
  /// Checks for idioms where an unused -autorelease is common.
165
  ///
166
  /// Returns true for this idiom which is common in property
167
  /// setters:
168
  ///
169
  ///   [backingValue autorelease];
170
  ///   backingValue = [newValue retain]; // in general a +1 assign
171
  ///
172
  /// For these as well:
173
  ///
174
  ///   [[var retain] autorelease];
175
  ///   return var;
176
  ///
177
14
  bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
178
14
    return isPlusOneAssignBeforeOrAfterAutorelease(E) ||
179
14
           
isReturnedAfterAutorelease(E)4
;
180
14
  }
181
182
4
  bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
183
4
    Expr *Rec = E->getInstanceReceiver();
184
4
    if (!Rec)
185
0
      return false;
186
4
187
4
    Decl *RefD = getReferencedDecl(Rec);
188
4
    if (!RefD)
189
0
      return false;
190
4
191
4
    Stmt *nextStmt = getNextStmt(E);
192
4
    if (!nextStmt)
193
0
      return false;
194
4
195
4
    // Check for "return <variable>;".
196
4
197
4
    if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
198
2
      return RefD == getReferencedDecl(RetS->getRetValue());
199
2
200
2
    return false;
201
2
  }
202
203
14
  bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
204
14
    Expr *Rec = E->getInstanceReceiver();
205
14
    if (!Rec)
206
0
      return false;
207
14
208
14
    Decl *RefD = getReferencedDecl(Rec);
209
14
    if (!RefD)
210
0
      return false;
211
14
212
14
    Stmt *prevStmt, *nextStmt;
213
14
    std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
214
14
215
14
    return isPlusOneAssignToVar(prevStmt, RefD) ||
216
14
           
isPlusOneAssignToVar(nextStmt, RefD)12
;
217
14
  }
218
219
26
  bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
220
26
    if (!S)
221
10
      return false;
222
16
223
16
    // Check for "RefD = [+1 retained object];".
224
16
225
16
    if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
226
9
      return (RefD == getReferencedDecl(Bop->getLHS())) && isPlusOneAssign(Bop);
227
9
    }
228
7
229
7
    if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
230
2
      if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
231
2
        if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
232
2
          return isPlusOne(VD->getInit());
233
0
      }
234
0
      return false;
235
0
    }
236
5
237
5
    return false;
238
5
  }
239
240
4
  Stmt *getNextStmt(Expr *E) {
241
4
    return getPreviousAndNextStmt(E).second;
242
4
  }
243
244
18
  std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
245
18
    Stmt *prevStmt = nullptr, *nextStmt = nullptr;
246
18
    if (!E)
247
0
      return std::make_pair(prevStmt, nextStmt);
248
18
249
18
    Stmt *OuterS = E, *InnerS;
250
54
    do {
251
54
      InnerS = OuterS;
252
54
      OuterS = StmtMap->getParent(InnerS);
253
54
    }
254
54
    while (OuterS && (isa<ParenExpr>(OuterS) ||
255
54
                      isa<CastExpr>(OuterS) ||
256
54
                      
isa<FullExpr>(OuterS)36
));
257
18
258
18
    if (!OuterS)
259
0
      return std::make_pair(prevStmt, nextStmt);
260
18
261
18
    Stmt::child_iterator currChildS = OuterS->child_begin();
262
18
    Stmt::child_iterator childE = OuterS->child_end();
263
18
    Stmt::child_iterator prevChildS = childE;
264
62
    for (; currChildS != childE; 
++currChildS44
) {
265
62
      if (*currChildS == InnerS)
266
18
        break;
267
44
      prevChildS = currChildS;
268
44
    }
269
18
270
18
    if (prevChildS != childE) {
271
6
      prevStmt = *prevChildS;
272
6
      if (auto *E = dyn_cast_or_null<Expr>(prevStmt))
273
4
        prevStmt = E->IgnoreImplicit();
274
6
    }
275
18
276
18
    if (currChildS == childE)
277
0
      return std::make_pair(prevStmt, nextStmt);
278
18
    ++currChildS;
279
18
    if (currChildS == childE)
280
2
      return std::make_pair(prevStmt, nextStmt);
281
16
282
16
    nextStmt = *currChildS;
283
16
    if (auto *E = dyn_cast_or_null<Expr>(nextStmt))
284
12
      nextStmt = E->IgnoreImplicit();
285
16
286
16
    return std::make_pair(prevStmt, nextStmt);
287
16
  }
288
289
33
  Decl *getReferencedDecl(Expr *E) {
290
33
    if (!E)
291
0
      return nullptr;
292
33
293
33
    E = E->IgnoreParenCasts();
294
33
    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
295
4
      switch (ME->getMethodFamily()) {
296
4
      case OMF_copy:
297
4
      case OMF_autorelease:
298
4
      case OMF_release:
299
4
      case OMF_retain:
300
4
        return getReferencedDecl(ME->getInstanceReceiver());
301
4
      default:
302
0
        return nullptr;
303
29
      }
304
29
    }
305
29
    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
306
17
      return DRE->getDecl();
307
12
    if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
308
0
      return ME->getMemberDecl();
309
12
    if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
310
12
      return IRE->getDecl();
311
0
312
0
    return nullptr;
313
0
  }
314
315
  /// Check if the retain/release is due to a GCD/XPC macro that are
316
  /// defined as:
317
  ///
318
  /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
319
  /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
320
  /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
321
  /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
322
  ///
323
  /// and return the top container which is the StmtExpr and the macro argument
324
  /// expression.
325
  void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
326
212
                        Expr *&Rec, SourceRange &RecRange) {
327
212
    SourceLocation Loc = Msg->getExprLoc();
328
212
    if (!Loc.isMacroID())
329
191
      return;
330
21
    SourceManager &SM = Pass.Ctx.getSourceManager();
331
21
    StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
332
21
                                                     Pass.Ctx.getLangOpts());
333
21
    bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
334
21
        .Case("dispatch_retain", true)
335
21
        .Case("dispatch_release", true)
336
21
        .Case("xpc_retain", true)
337
21
        .Case("xpc_release", true)
338
21
        .Default(false);
339
21
    if (!isGCDOrXPC)
340
9
      return;
341
12
342
12
    StmtExpr *StmtE = nullptr;
343
12
    Stmt *S = Msg;
344
60
    while (S) {
345
60
      if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
346
12
        StmtE = SE;
347
12
        break;
348
12
      }
349
48
      S = StmtMap->getParent(S);
350
48
    }
351
12
352
12
    if (!StmtE)
353
0
      return;
354
12
355
12
    Stmt::child_range StmtExprChild = StmtE->children();
356
12
    if (StmtExprChild.begin() == StmtExprChild.end())
357
0
      return;
358
12
    auto *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild.begin());
359
12
    if (!CompS)
360
0
      return;
361
12
362
12
    Stmt::child_range CompStmtChild = CompS->children();
363
12
    if (CompStmtChild.begin() == CompStmtChild.end())
364
0
      return;
365
12
    auto *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild.begin());
366
12
    if (!DeclS)
367
0
      return;
368
12
    if (!DeclS->isSingleDecl())
369
0
      return;
370
12
    VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
371
12
    if (!VD)
372
0
      return;
373
12
    Expr *Init = VD->getInit();
374
12
    if (!Init)
375
0
      return;
376
12
377
12
    RecContainer = StmtE;
378
12
    Rec = Init->IgnoreParenImpCasts();
379
12
    if (FullExpr *FE = dyn_cast<FullExpr>(Rec))
380
0
      Rec = FE->getSubExpr()->IgnoreParenImpCasts();
381
12
    RecRange = Rec->getSourceRange();
382
12
    if (SM.isMacroArgExpansion(RecRange.getBegin()))
383
12
      RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
384
12
    if (SM.isMacroArgExpansion(RecRange.getEnd()))
385
12
      RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
386
12
  }
387
388
216
  void clearDiagnostics(SourceLocation loc) const {
389
216
    Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
390
216
                            diag::err_unavailable,
391
216
                            diag::err_unavailable_message,
392
216
                            loc);
393
216
  }
394
395
117
  bool isDelegateMessage(Expr *E) const {
396
117
    if (!E) 
return false0
;
397
117
398
117
    E = E->IgnoreParenCasts();
399
117
400
117
    // Also look through property-getter sugar.
401
117
    if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
402
1
      E = pseudoOp->getResultExpr()->IgnoreImplicit();
403
117
404
117
    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
405
10
      return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
406
107
407
107
    return false;
408
107
  }
409
410
107
  bool isInAtFinally(Expr *E) const {
411
107
    assert(E);
412
107
    Stmt *S = E;
413
377
    while (S) {
414
272
      if (isa<ObjCAtFinallyStmt>(S))
415
2
        return true;
416
270
      S = StmtMap->getParent(S);
417
270
    }
418
107
419
107
    
return false105
;
420
107
  }
421
422
405
  bool isRemovable(Expr *E) const {
423
405
    return Removables.count(E);
424
405
  }
425
426
255
  bool tryRemoving(Expr *E) const {
427
255
    if (isRemovable(E)) {
428
135
      Pass.TA.removeStmt(E);
429
135
      return true;
430
135
    }
431
120
432
120
    Stmt *parent = StmtMap->getParent(E);
433
120
434
120
    if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
435
54
      return tryRemoving(castE);
436
66
437
66
    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
438
18
      return tryRemoving(parenE);
439
48
440
48
    if (BinaryOperator *
441
48
          bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
442
18
      if (bopE->getOpcode() == BO_Comma && 
bopE->getLHS() == E4
&&
443
18
          
isRemovable(bopE)4
) {
444
4
        Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
445
4
        return true;
446
4
      }
447
44
    }
448
44
449
44
    return false;
450
44
  }
451
452
};
453
454
} // anonymous namespace
455
456
85
void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
457
85
  BodyTransform<RetainReleaseDeallocRemover> trans(pass);
458
85
  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
459
85
}