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