annotate clang/lib/ARCMigrate/TransProtectedScope.cpp @ 252:1f2b6ac9f198 llvm-original

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