Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/ARCMigrate/TransProtectedScope.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- TransProtectedScope.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
// Adds brackets in case statements that "contain" initialization of retaining
10
// variable, thus emitting the "switch case is in protected scope" error.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "Transforms.h"
15
#include "Internals.h"
16
#include "clang/AST/ASTContext.h"
17
#include "clang/Sema/SemaDiagnostic.h"
18
19
using namespace clang;
20
using namespace arcmt;
21
using namespace trans;
22
23
namespace {
24
25
class LocalRefsCollector : public RecursiveASTVisitor<LocalRefsCollector> {
26
  SmallVectorImpl<DeclRefExpr *> &Refs;
27
28
public:
29
  LocalRefsCollector(SmallVectorImpl<DeclRefExpr *> &refs)
30
403
    : Refs(refs) { }
31
32
918
  bool VisitDeclRefExpr(DeclRefExpr *E) {
33
918
    if (ValueDecl *D = E->getDecl())
34
918
      if (D->getDeclContext()->getRedeclContext()->isFunctionOrMethod())
35
752
        Refs.push_back(E);
36
918
    return true;
37
918
  }
38
};
39
40
struct CaseInfo {
41
  SwitchCase *SC;
42
  SourceRange Range;
43
  enum {
44
    St_Unchecked,
45
    St_CannotFix,
46
    St_Fixed
47
  } State;
48
49
0
  CaseInfo() : SC(nullptr), State(St_Unchecked) {}
50
  CaseInfo(SwitchCase *S, SourceRange Range)
51
18
    : SC(S), Range(Range), State(St_Unchecked) {}
52
};
53
54
class CaseCollector : public RecursiveASTVisitor<CaseCollector> {
55
  ParentMap &PMap;
56
  SmallVectorImpl<CaseInfo> &Cases;
57
58
public:
59
  CaseCollector(ParentMap &PMap, SmallVectorImpl<CaseInfo> &Cases)
60
403
    : PMap(PMap), Cases(Cases) { }
61
62
6
  bool VisitSwitchStmt(SwitchStmt *S) {
63
6
    SwitchCase *Curr = S->getSwitchCaseList();
64
6
    if (!Curr)
65
0
      return true;
66
6
    Stmt *Parent = getCaseParent(Curr);
67
6
    Curr = Curr->getNextSwitchCase();
68
6
    // Make sure all case statements are in the same scope.
69
18
    while (Curr) {
70
12
      if (getCaseParent(Curr) != Parent)
71
0
        return true;
72
12
      Curr = Curr->getNextSwitchCase();
73
12
    }
74
6
75
6
    SourceLocation NextLoc = S->getEndLoc();
76
6
    Curr = S->getSwitchCaseList();
77
6
    // We iterate over case statements in reverse source-order.
78
24
    while (Curr) {
79
18
      Cases.push_back(
80
18
          CaseInfo(Curr, SourceRange(Curr->getBeginLoc(), NextLoc)));
81
18
      NextLoc = Curr->getBeginLoc();
82
18
      Curr = Curr->getNextSwitchCase();
83
18
    }
84
6
    return true;
85
6
  }
86
87
18
  Stmt *getCaseParent(SwitchCase *S) {
88
18
    Stmt *Parent = PMap.getParent(S);
89
20
    while (Parent && (isa<SwitchCase>(Parent) || 
isa<LabelStmt>(Parent)18
))
90
2
      Parent = PMap.getParent(Parent);
91
18
    return Parent;
92
18
  }
93
};
94
95
class ProtectedScopeFixer {
96
  MigrationPass &Pass;
97
  SourceManager &SM;
98
  SmallVector<CaseInfo, 16> Cases;
99
  SmallVector<DeclRefExpr *, 16> LocalRefs;
100
101
public:
102
  ProtectedScopeFixer(BodyContext &BodyCtx)
103
    : Pass(BodyCtx.getMigrationContext().Pass),
104
403
      SM(Pass.Ctx.getSourceManager()) {
105
403
106
403
    CaseCollector(BodyCtx.getParentMap(), Cases)
107
403
        .TraverseStmt(BodyCtx.getTopStmt());
108
403
    LocalRefsCollector(LocalRefs).TraverseStmt(BodyCtx.getTopStmt());
109
403
110
403
    SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange();
111
403
    const CapturedDiagList &DiagList = Pass.getDiags();
112
403
    // Copy the diagnostics so we don't have to worry about invaliding iterators
113
403
    // from the diagnostic list.
114
403
    SmallVector<StoredDiagnostic, 16> StoredDiags;
115
403
    StoredDiags.append(DiagList.begin(), DiagList.end());
116
403
    SmallVectorImpl<StoredDiagnostic>::iterator
117
403
        I = StoredDiags.begin(), E = StoredDiags.end();
118
6.19k
    while (I != E) {
119
5.79k
      if (I->getID() == diag::err_switch_into_protected_scope &&
120
5.79k
          
isInRange(I->getLocation(), BodyRange)141
) {
121
12
        handleProtectedScopeError(I, E);
122
12
        continue;
123
12
      }
124
5.78k
      ++I;
125
5.78k
    }
126
403
  }
127
128
  void handleProtectedScopeError(
129
                             SmallVectorImpl<StoredDiagnostic>::iterator &DiagI,
130
12
                             SmallVectorImpl<StoredDiagnostic>::iterator DiagE){
131
12
    Transaction Trans(Pass.TA);
132
12
    assert(DiagI->getID() == diag::err_switch_into_protected_scope);
133
12
    SourceLocation ErrLoc = DiagI->getLocation();
134
12
    bool handledAllNotes = true;
135
12
    ++DiagI;
136
38
    for (; DiagI != DiagE && 
DiagI->getLevel() == DiagnosticsEngine::Note36
;
137
26
         ++DiagI) {
138
26
      if (!handleProtectedNote(*DiagI))
139
1
        handledAllNotes = false;
140
26
    }
141
12
142
12
    if (handledAllNotes)
143
11
      Pass.TA.clearDiagnostic(diag::err_switch_into_protected_scope, ErrLoc);
144
12
  }
145
146
26
  bool handleProtectedNote(const StoredDiagnostic &Diag) {
147
26
    assert(Diag.getLevel() == DiagnosticsEngine::Note);
148
26
149
112
    for (unsigned i = 0; i != Cases.size(); 
i++86
) {
150
112
      CaseInfo &info = Cases[i];
151
112
      if (isInRange(Diag.getLocation(), info.Range)) {
152
26
153
26
        if (info.State == CaseInfo::St_Unchecked)
154
8
          tryFixing(info);
155
26
        assert(info.State != CaseInfo::St_Unchecked);
156
26
157
26
        if (info.State == CaseInfo::St_Fixed) {
158
25
          Pass.TA.clearDiagnostic(Diag.getID(), Diag.getLocation());
159
25
          return true;
160
25
        }
161
1
        return false;
162
1
      }
163
112
    }
164
26
165
26
    
return false0
;
166
26
  }
167
168
8
  void tryFixing(CaseInfo &info) {
169
8
    assert(info.State == CaseInfo::St_Unchecked);
170
8
    if (hasVarReferencedOutside(info)) {
171
1
      info.State = CaseInfo::St_CannotFix;
172
1
      return;
173
1
    }
174
7
175
7
    Pass.TA.insertAfterToken(info.SC->getColonLoc(), " {");
176
7
    Pass.TA.insert(info.Range.getEnd(), "}\n");
177
7
    info.State = CaseInfo::St_Fixed;
178
7
  }
179
180
8
  bool hasVarReferencedOutside(CaseInfo &info) {
181
39
    for (unsigned i = 0, e = LocalRefs.size(); i != e; 
++i31
) {
182
32
      DeclRefExpr *DRE = LocalRefs[i];
183
32
      if (isInRange(DRE->getDecl()->getLocation(), info.Range) &&
184
32
          
!isInRange(DRE->getLocation(), info.Range)4
)
185
1
        return true;
186
32
    }
187
8
    
return false7
;
188
8
  }
189
190
289
  bool isInRange(SourceLocation Loc, SourceRange R) {
191
289
    if (Loc.isInvalid())
192
0
      return false;
193
289
    return !SM.isBeforeInTranslationUnit(Loc, R.getBegin()) &&
194
289
            
SM.isBeforeInTranslationUnit(Loc, R.getEnd())132
;
195
289
  }
196
};
197
198
} // anonymous namespace
199
200
403
void ProtectedScopeTraverser::traverseBody(BodyContext &BodyCtx) {
201
403
  ProtectedScopeFixer Fix(BodyCtx);
202
403
}