xref: /aosp_15_r20/external/clang/lib/ARCMigrate/TransProtectedScope.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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