clang  8.0.0svn
TransProtectedScope.cpp
Go to the documentation of this file.
1 //===--- TransProtectedScope.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 // Adds brackets in case statements that "contain" initialization of retaining
11 // variable, thus emitting the "switch case is in protected scope" error.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "Transforms.h"
16 #include "Internals.h"
17 #include "clang/AST/ASTContext.h"
19 
20 using namespace clang;
21 using namespace arcmt;
22 using namespace trans;
23 
24 namespace {
25 
26 class LocalRefsCollector : public RecursiveASTVisitor<LocalRefsCollector> {
28 
29 public:
30  LocalRefsCollector(SmallVectorImpl<DeclRefExpr *> &refs)
31  : Refs(refs) { }
32 
33  bool VisitDeclRefExpr(DeclRefExpr *E) {
34  if (ValueDecl *D = E->getDecl())
35  if (D->getDeclContext()->getRedeclContext()->isFunctionOrMethod())
36  Refs.push_back(E);
37  return true;
38  }
39 };
40 
41 struct CaseInfo {
42  SwitchCase *SC;
43  SourceRange Range;
44  enum {
45  St_Unchecked,
46  St_CannotFix,
47  St_Fixed
48  } State;
49 
50  CaseInfo() : SC(nullptr), State(St_Unchecked) {}
51  CaseInfo(SwitchCase *S, SourceRange Range)
52  : SC(S), Range(Range), State(St_Unchecked) {}
53 };
54 
55 class CaseCollector : public RecursiveASTVisitor<CaseCollector> {
56  ParentMap &PMap;
58 
59 public:
60  CaseCollector(ParentMap &PMap, SmallVectorImpl<CaseInfo> &Cases)
61  : PMap(PMap), Cases(Cases) { }
62 
63  bool VisitSwitchStmt(SwitchStmt *S) {
64  SwitchCase *Curr = S->getSwitchCaseList();
65  if (!Curr)
66  return true;
67  Stmt *Parent = getCaseParent(Curr);
68  Curr = Curr->getNextSwitchCase();
69  // Make sure all case statements are in the same scope.
70  while (Curr) {
71  if (getCaseParent(Curr) != Parent)
72  return true;
73  Curr = Curr->getNextSwitchCase();
74  }
75 
76  SourceLocation NextLoc = S->getEndLoc();
77  Curr = S->getSwitchCaseList();
78  // We iterate over case statements in reverse source-order.
79  while (Curr) {
80  Cases.push_back(
81  CaseInfo(Curr, SourceRange(Curr->getBeginLoc(), NextLoc)));
82  NextLoc = Curr->getBeginLoc();
83  Curr = Curr->getNextSwitchCase();
84  }
85  return true;
86  }
87 
88  Stmt *getCaseParent(SwitchCase *S) {
89  Stmt *Parent = PMap.getParent(S);
90  while (Parent && (isa<SwitchCase>(Parent) || isa<LabelStmt>(Parent)))
91  Parent = PMap.getParent(Parent);
92  return Parent;
93  }
94 };
95 
96 class ProtectedScopeFixer {
97  MigrationPass &Pass;
101 
102 public:
103  ProtectedScopeFixer(BodyContext &BodyCtx)
104  : Pass(BodyCtx.getMigrationContext().Pass),
105  SM(Pass.Ctx.getSourceManager()) {
106 
107  CaseCollector(BodyCtx.getParentMap(), Cases)
108  .TraverseStmt(BodyCtx.getTopStmt());
109  LocalRefsCollector(LocalRefs).TraverseStmt(BodyCtx.getTopStmt());
110 
111  SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange();
112  const CapturedDiagList &DiagList = Pass.getDiags();
113  // Copy the diagnostics so we don't have to worry about invaliding iterators
114  // from the diagnostic list.
116  StoredDiags.append(DiagList.begin(), DiagList.end());
118  I = StoredDiags.begin(), E = StoredDiags.end();
119  while (I != E) {
120  if (I->getID() == diag::err_switch_into_protected_scope &&
121  isInRange(I->getLocation(), BodyRange)) {
122  handleProtectedScopeError(I, E);
123  continue;
124  }
125  ++I;
126  }
127  }
128 
129  void handleProtectedScopeError(
132  Transaction Trans(Pass.TA);
133  assert(DiagI->getID() == diag::err_switch_into_protected_scope);
134  SourceLocation ErrLoc = DiagI->getLocation();
135  bool handledAllNotes = true;
136  ++DiagI;
137  for (; DiagI != DiagE && DiagI->getLevel() == DiagnosticsEngine::Note;
138  ++DiagI) {
139  if (!handleProtectedNote(*DiagI))
140  handledAllNotes = false;
141  }
142 
143  if (handledAllNotes)
144  Pass.TA.clearDiagnostic(diag::err_switch_into_protected_scope, ErrLoc);
145  }
146 
147  bool handleProtectedNote(const StoredDiagnostic &Diag) {
148  assert(Diag.getLevel() == DiagnosticsEngine::Note);
149 
150  for (unsigned i = 0; i != Cases.size(); i++) {
151  CaseInfo &info = Cases[i];
152  if (isInRange(Diag.getLocation(), info.Range)) {
153 
154  if (info.State == CaseInfo::St_Unchecked)
155  tryFixing(info);
156  assert(info.State != CaseInfo::St_Unchecked);
157 
158  if (info.State == CaseInfo::St_Fixed) {
159  Pass.TA.clearDiagnostic(Diag.getID(), Diag.getLocation());
160  return true;
161  }
162  return false;
163  }
164  }
165 
166  return false;
167  }
168 
169  void tryFixing(CaseInfo &info) {
170  assert(info.State == CaseInfo::St_Unchecked);
171  if (hasVarReferencedOutside(info)) {
172  info.State = CaseInfo::St_CannotFix;
173  return;
174  }
175 
176  Pass.TA.insertAfterToken(info.SC->getColonLoc(), " {");
177  Pass.TA.insert(info.Range.getEnd(), "}\n");
178  info.State = CaseInfo::St_Fixed;
179  }
180 
181  bool hasVarReferencedOutside(CaseInfo &info) {
182  for (unsigned i = 0, e = LocalRefs.size(); i != e; ++i) {
183  DeclRefExpr *DRE = LocalRefs[i];
184  if (isInRange(DRE->getDecl()->getLocation(), info.Range) &&
185  !isInRange(DRE->getLocation(), info.Range))
186  return true;
187  }
188  return false;
189  }
190 
191  bool isInRange(SourceLocation Loc, SourceRange R) {
192  if (Loc.isInvalid())
193  return false;
194  return !SM.isBeforeInTranslationUnit(Loc, R.getBegin()) &&
195  SM.isBeforeInTranslationUnit(Loc, R.getEnd());
196  }
197 };
198 
199 } // anonymous namespace
200 
202  ProtectedScopeFixer Fix(BodyCtx);
203 }
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Stmt.h:1201
Defines the clang::ASTContext interface.
unsigned getID() const
Definition: Diagnostic.h:1457
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Stmt - This represents one statement.
Definition: Stmt.h:66
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
Definition: Diagnostic.h:1436
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
Stmt * getParent(Stmt *) const
Definition: ParentMap.cpp:123
const CapturedDiagList & getDiags() const
Definition: Internals.h:164
LineState State
iterator begin() const
Definition: Internals.h:40
TextDiagnosticBuffer::DiagList DiagList
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
NodeId Parent
Definition: ASTDiff.cpp:192
bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)
SourceLocation getLocation() const
Definition: Expr.h:1073
void traverseBody(BodyContext &BodyCtx) override
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:640
DiagnosticsEngine::Level getLevel() const
Definition: Diagnostic.h:1458
void insertAfterToken(SourceLocation loc, StringRef text)
SourceLocation getEnd() const
ValueDecl * getDecl()
Definition: Expr.h:1065
const SourceManager & SM
Definition: Format.cpp:1475
Encodes a location in the source.
const SwitchCase * getSwitchCaseList() const
Definition: Stmt.h:1157
Dataflow Directional Tag Classes.
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.h:785
const FullSourceLoc & getLocation() const
Definition: Diagnostic.h:1459
SwitchStmt - This represents a &#39;switch&#39; stmt.
Definition: Stmt.h:1117
const SwitchCase * getNextSwitchCase() const
Definition: Stmt.h:765
TransformActions & TA
Definition: Internals.h:151
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:268
void insert(SourceLocation loc, StringRef text)
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:980
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Definition: DeclBase.h:425