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