Produced by Araxis Merge on 9/25/2018 2:13:06 PM Central Daylight Time. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.
# | Location | File | Last Modified |
---|---|---|---|
1 | build 3.zip\build 3\MHLTH_YS_137_Source\JavaScript\resources\javaJDF-1.8.0\src\com\sun\tools\javac\comp | Flow.java | Mon Jan 22 14:47:06 2018 UTC |
2 | build 3.zip\build 3\MHLTH_YS_137_Source\JavaScript\resources\javaJDF-1.8.0\src\com\sun\tools\javac\comp | Flow.java | Wed Sep 12 16:49:30 2018 UTC |
Description | Between Files 1 and 2 |
|
---|---|---|
Text Blocks | Lines | |
Unchanged | 5 | 5236 |
Changed | 4 | 8 |
Inserted | 0 | 0 |
Removed | 0 | 0 |
Whitespace | |
---|---|
Character case | Differences in character case are significant |
Line endings | Differences in line endings (CR and LF characters) are ignored |
CR/LF characters | Not shown in the comparison detail |
No regular expressions were active.
1 | /* | |
2 | * Copyrig ht (c) 199 9, 2015, O racle and/ or its aff iliates. A ll rights reserved. | |
3 | * DO NOT ALTER OR R EMOVE COPY RIGHT NOTI CES OR THI S FILE HEA DER. | |
4 | * | |
5 | * This co de is free software; you can r edistribut e it and/o r modify i t | |
6 | * under t he terms o f the GNU General Pu blic Licen se version 2 only, a s | |
7 | * publish ed by the Free Softw are Founda tion. Ora cle design ates this | |
8 | * particu lar file a s subject to the "Cl asspath" e xception a s provided | |
9 | * by Orac le in the LICENSE fi le that ac companied this code. | |
10 | * | |
11 | * This co de is dist ributed in the hope that it wi ll be usef ul, but WI THOUT | |
12 | * ANY WAR RANTY; wit hout even the implie d warranty of MERCHA NTABILITY or | |
13 | * FITNESS FOR A PAR TICULAR PU RPOSE. Se e the GNU General Pu blic Licen se | |
14 | * version 2 for mor e details (a copy is included in the LIC ENSE file that | |
15 | * accompa nied this code). | |
16 | * | |
17 | * You sho uld have r eceived a copy of th e GNU Gene ral Public License v ersion | |
18 | * 2 along with this work; if not, write to the Fr ee Softwar e Foundati on, | |
19 | * Inc., 5 1 Franklin St, Fifth Floor, Bo ston, MA 0 2110-1301 USA. | |
20 | * | |
21 | * Please contact Or acle, 500 Oracle Par kway, Redw ood Shores , CA 94065 USA | |
22 | * or visi t www.orac le.com if you need a dditional informatio n or have any | |
23 | * questio ns. | |
24 | */ | |
25 | ||
26 | //todo: on e might el iminate un inits.andS ets when m onotonic | |
27 | ||
28 | package co m.sun.tool s.javac.co mp; | |
29 | ||
30 | import jav a.util.Has hMap; | |
31 | ||
32 | import com .sun.tools .javac.cod e.*; | |
33 | import com .sun.tools .javac.tre e.*; | |
34 | import com .sun.tools .javac.uti l.*; | |
35 | import com .sun.tools .javac.uti l.JCDiagno stic.Diagn osticPosit ion; | |
36 | ||
37 | import com .sun.tools .javac.cod e.Symbol.* ; | |
38 | import com .sun.tools .javac.tre e.JCTree.* ; | |
39 | ||
40 | import sta tic com.su n.tools.ja vac.code.F lags.*; | |
41 | import sta tic com.su n.tools.ja vac.code.F lags.BLOCK ; | |
42 | import sta tic com.su n.tools.ja vac.code.K inds.*; | |
43 | import sta tic com.su n.tools.ja vac.code.T ypeTag.BOO LEAN; | |
44 | import sta tic com.su n.tools.ja vac.code.T ypeTag.VOI D; | |
45 | import sta tic com.su n.tools.ja vac.tree.J CTree.Tag. *; | |
46 | ||
47 | /** This p ass implem ents dataf low analys is for Jav a programs though | |
48 | * differ ent AST vi sitor step s. Livenes s analysis (see Aliv eAnalyzer) checks th at | |
49 | * every statement is reachab le. Except ion analys is (see Fl owAnalyzer ) ensures that | |
50 | * every checked ex ception th at is thro wn is decl ared or ca ught. Def inite assi gnment ana lysis | |
51 | * (see A ssignAnaly zer) ensur es that ea ch variabl e is assig ned when u sed. Defi nite | |
52 | * unassi gnment ana lysis (see AssignAna lyzer) in ensures th at no fina l variable | |
53 | * is ass igned more than once . Finally, local var iable capt ure analys is (see Ca ptureAnaly zer) | |
54 | * determ ines that local vari ables acce ssed withi n the scop e of an in ner class/ lambda | |
55 | * are ei ther final or effect ively-fina l. | |
56 | * | |
57 | * <p>The JLS has a number of problems in the | |
58 | * specif ication of these flo w analysis problems. This impl ementation | |
59 | * attemp ts to addr ess those issues. | |
60 | * | |
61 | * <p>Fir st, there is no acco mmodation for a fina lly clause that cann ot | |
62 | * comple te normall y. For liv eness anal ysis, an i ntervening finally | |
63 | * clause can cause a break, continue, or return not to rea ch its | |
64 | * target . For exc eption ana lysis, an intervenin g finally clause can | |
65 | * cause any except ion to be "caught". For DA/DU analysis, the final ly | |
66 | * clause can preve nt a trans fer of con trol from propagatin g DA/DU | |
67 | * state to the tar get. In a ddition, c ode in the finally c lause can | |
68 | * affect the DA/DU status of variables . | |
69 | * | |
70 | * <p>For try state ments, we introduce the idea o f a variab le being | |
71 | * defini tely unass igned "eve rywhere" i n a block. A variab le V is | |
72 | * "unass igned ever ywhere" in a block i ff it is u nassigned at the | |
73 | * beginn ing of the block and there is no reachab le assignm ent to V | |
74 | * in the block. A n assignme nt V=e is reachable iff V is n ot DA | |
75 | * after e. Then w e can say that V is DU at the beginning of the | |
76 | * catch block iff V is DU ev erywhere i n the try block. Si milarly, V | |
77 | * is DU at the beg inning of the finall y block if f V is DU everywhere | |
78 | * in the try block and in ev ery catch block. Sp ecifically , the | |
79 | * follow ing bullet is added to 16.2.2 | |
80 | * <pre> | |
81 | * V is <em>una ssigned ev erywhere</ em> in a b lock if it is | |
82 | * un assigned b efore the block and there is n o reachabl e | |
83 | * as signment t o V within the block . | |
84 | * </pre> | |
85 | * <p>In 16.2.15, t he third b ullet (and all of it s sub-bull ets) for a ll | |
86 | * try bl ocks is ch anged to | |
87 | * <pre> | |
88 | * V is definit ely unassi gned befor e a catch block iff V is | |
89 | * de finitely u nassigned everywhere in the tr y block. | |
90 | * </pre> | |
91 | * <p>The last bull et (and al l of its s ub-bullets ) for try blocks tha t | |
92 | * have a finally b lock is ch anged to | |
93 | * <pre> | |
94 | * V is definit ely unassi gned befor e the fina lly block iff | |
95 | * V is definit ely unassi gned every where in t he try blo ck | |
96 | * an d everywhe re in each catch blo ck of the try statem ent. | |
97 | * </pre> | |
98 | * <p>In addition, | |
99 | * <pre> | |
100 | * V is definit ely assign ed at the end of a c onstructor iff | |
101 | * V is definit ely assign ed after t he block t hat is the body | |
102 | * of the const ructor and V is defi nitely ass igned at e very | |
103 | * re turn that can return from the constructo r. | |
104 | * </pre> | |
105 | * <p>In addition, each conti nue statem ent with t he loop as its targe t | |
106 | * is tre ated as a jump to th e end of t he loop bo dy, and "i ntervening " | |
107 | * finall y clauses are treate d as follo ws: V is D A "due to the | |
108 | * contin ue" iff V is DA befo re the con tinue stat ement or V is DA at | |
109 | * the en d of any i ntervening finally b lock. V i s DU "due to the | |
110 | * contin ue" iff an y interven ing finall y cannot c omplete no rmally or V | |
111 | * is DU at the end of every intervenin g finally block. Th is "due to | |
112 | * the co ntinue" co ncept is t hen used i n the spec for the l oops. | |
113 | * | |
114 | * <p>Sim ilarly, br eak statem ents must consider i ntervening finally | |
115 | * blocks . For liv eness anal ysis, a br eak statem ent for wh ich any | |
116 | * interv ening fina lly cannot complete normally i s not cons idered to | |
117 | * cause the target statement to be abl e to compl ete normal ly. Then | |
118 | * we say V is DA " due to the break" if f V is DA before the break or | |
119 | * V is D A at the e nd of any intervenin g finally block. V is DU "due | |
120 | * to the break" if f any inte rvening fi nally cann ot complet e normally | |
121 | * or V i s DU at th e break an d at the e nd of ever y interven ing | |
122 | * finall y block. (I suspect this latt er conditi on can be | |
123 | * simpli fied.) Th is "due to the break " is then used in th e spec for | |
124 | * all st atements t hat can be "broken". | |
125 | * | |
126 | * <p>The return st atement is treated s imilarly. V is DA " due to a | |
127 | * return statement " iff V is DA before the retur n statemen t or V is | |
128 | * DA at the end of any inter vening fin ally block . Note th at we | |
129 | * don't have to wo rry about the return expressio n because this | |
130 | * concep t is only used for c onstrucror s. | |
131 | * | |
132 | * <p>The re is no s pec in the JLS for w hen a vari able is de finitely | |
133 | * assign ed at the end of a c onstructor , which is needed fo r final | |
134 | * fields (8.3.1.2) . We impl ement the rule that V is DA at the end | |
135 | * of the construct or iff it is DA and the end of the body of the | |
136 | * constr uctor and V is DA "d ue to" eve ry return of the con structor. | |
137 | * | |
138 | * <p>Int ervening f inally blo cks simila rly affect exception analysis. An | |
139 | * interv ening fina lly that c annot comp lete norma lly allows us to ign ore | |
140 | * an oth erwise unc aught exce ption. | |
141 | * | |
142 | * <p>To implement the semant ics of int ervening f inally cla uses, all | |
143 | * nonloc al transfe rs (break, continue, return, t hrow, meth od call th at | |
144 | * can th row a chec ked except ion, and a construct or invocat ion that c an | |
145 | * thrown a checked exception ) are reco rded in a queue, and removed | |
146 | * from t he queue w hen we com plete proc essing the target of the | |
147 | * nonloc al transfe r. This a llows us t o modify t he queue i n accordan ce | |
148 | * with t he above r ules when we encount er a final ly clause. The only | |
149 | * except ion to thi s [no pun intended] is that ch ecked exce ptions tha t | |
150 | * are kn own to be caught or declared t o be caugh t in the e nclosing | |
151 | * method are not r ecorded in the queue , but inst ead are re corded in a | |
152 | * global variable "{@code Se t<Type> th rown}" tha t records the type o f all | |
153 | * except ions that can be thr own. | |
154 | * | |
155 | * <p>Oth er minor i ssues the treatment of members of other classes | |
156 | * (alway s consider ed DA exce pt that wi thin an an onymous cl ass | |
157 | * constr uctor, whe re DA stat us from th e enclosin g scope is | |
158 | * preser ved), trea tment of t he case ex pression ( V is DA be fore the | |
159 | * case e xpression iff V is D A after th e switch e xpression) , | |
160 | * treatm ent of var iables dec lared in a switch bl ock (the i mplied | |
161 | * DA/DU status aft er the swi tch expres sion is DU and not D A for | |
162 | * variab les define d in a swi tch block) , the trea tment of b oolean ?: | |
163 | * expres sions (The JLS rules only hand le b and c non-boole an; the | |
164 | * new ru le is that if b and c are bool ean valued , then V i s | |
165 | * (un)as signed aft er a?b:c w hen true/f alse iff V is (un)as signed | |
166 | * after b when tru e/false an d V is (un )assigned after c wh en | |
167 | * true/f alse). | |
168 | * | |
169 | * <p>The re is the remaining question o f what syn tactic for ms constit ute a | |
170 | * refere nce to a v ariable. It is conv entional t o allow th is.x on th e | |
171 | * left-h and-side t o initiali ze a final instance field name d x, yet | |
172 | * this.x isn't con sidered a "use" when appearing on a righ t-hand-sid e | |
173 | * in mos t implemen tations. Should par entheses a ffect what is | |
174 | * consid ered a var iable refe rence? Th e simplest rule woul d be to | |
175 | * allow unqualifie d forms on ly, parent heses opti onal, and phase out | |
176 | * suppor t for assi gning to a final fie ld via thi s.x. | |
177 | * | |
178 | * <p><b> This is NO T part of any suppor ted API. | |
179 | * If you write cod e that dep ends on th is, you do so at you r own risk . | |
180 | * This c ode and it s internal interface s are subj ect to cha nge or | |
181 | * deleti on without notice.</ b> | |
182 | */ | |
183 | public cla ss Flow { | |
184 | protec ted static final Con text.Key<F low> flowK ey = | |
185 | ne w Context. Key<Flow>( ); | |
186 | ||
187 | privat e final Na mes names; | |
188 | privat e final Lo g log; | |
189 | privat e final Sy mtab syms; | |
190 | privat e final Ty pes types; | |
191 | privat e final Ch eck chk; | |
192 | privat e Tr eeMaker ma ke; | |
193 | privat e final Re solve rs; | |
194 | privat e final JC Diagnostic .Factory d iags; | |
195 | privat e Env<Attr Context> a ttrEnv; | |
196 | privat e Li nt lint; | |
197 | privat e final bo olean allo wImprovedR ethrowAnal ysis; | |
198 | privat e final bo olean allo wImprovedC atchAnalys is; | |
199 | privat e final bo olean allo wEffective lyFinalInI nnerClasse s; | |
200 | privat e final bo olean enfo rceThisDot Init; | |
201 | ||
202 | public static Fl ow instanc e(Context context) { | |
203 | Fl ow instanc e = contex t.get(flow Key); | |
204 | if (instance == null) | |
205 | instance = new Flo w(context) ; | |
206 | re turn insta nce; | |
207 | } | |
208 | ||
209 | public void anal yzeTree(En v<AttrCont ext> env, TreeMaker make) { | |
210 | ne w AliveAna lyzer().an alyzeTree( env, make) ; | |
211 | ne w AssignAn alyzer().a nalyzeTree (env); | |
212 | ne w FlowAnal yzer().ana lyzeTree(e nv, make); | |
213 | ne w CaptureA nalyzer(). analyzeTre e(env, mak e); | |
214 | } | |
215 | ||
216 | public void anal yzeLambda( Env<AttrCo ntext> env , JCLambda that, Tre eMaker mak e, boolean speculati ve) { | |
217 | Lo g.Diagnost icHandler diagHandle r = null; | |
218 | // we need to disable d iagnostics temporari ly; the pr oblem is t hat if | |
219 | // a lambda e xpression contains e .g. an unr eachable s tatement, an error | |
220 | // message wi ll be repo rted and w ill cause compilatio n to skip the flow a nalyis | |
221 | // step - if we suppres s diagnost ics, we wo n't stop a t Attr for flow-anal ysis | |
222 | // related er rors, whic h will all ow for mor e errors t o be detec ted | |
223 | if (!specula tive) { | |
224 | diagHand ler = new Log.Discar dDiagnosti cHandler(l og); | |
225 | } | |
226 | tr y { | |
227 | new Aliv eAnalyzer( ).analyzeT ree(env, t hat, make) ; | |
228 | } finally { | |
229 | if (!spe culative) { | |
230 | log. popDiagnos ticHandler (diagHandl er); | |
231 | } | |
232 | } | |
233 | } | |
234 | ||
235 | public List<Type > analyzeL ambdaThrow nTypes(fin al Env<Att rContext> env, | |
236 | JCLambda that, Tre eMaker mak e) { | |
237 | // we need to disable d iagnostics temporari ly; the pr oblem is t hat if | |
238 | // a lambda e xpression contains e .g. an unr eachable s tatement, an error | |
239 | // message wi ll be repo rted and w ill cause compilatio n to skip the flow a nalyis | |
240 | // step - if we suppres s diagnost ics, we wo n't stop a t Attr for flow-anal ysis | |
241 | // related er rors, whic h will all ow for mor e errors t o be detec ted | |
242 | Lo g.Diagnost icHandler diagHandle r = new Lo g.DiscardD iagnosticH andler(log ); | |
243 | tr y { | |
244 | new Assi gnAnalyzer () { | |
245 | Scop e enclosed Symbols = new Scope( env.enclCl ass.sym); | |
246 | @Ove rride | |
247 | publ ic void vi sitVarDef( JCVariable Decl tree) { | |
248 | enclosedSy mbols.ente r(tree.sym ); | |
249 | super.visi tVarDef(tr ee); | |
250 | } | |
251 | @Ove rride | |
252 | prot ected bool ean tracka ble(VarSym bol sym) { | |
253 | return enc losedSymbo ls.include s(sym) && | |
254 | sym .owner.kin d == MTH; | |
255 | } | |
256 | }.analyz eTree(env, that); | |
257 | LambdaFl owAnalyzer flowAnaly zer = new LambdaFlow Analyzer() ; | |
258 | flowAnal yzer.analy zeTree(env , that, ma ke); | |
259 | return f lowAnalyze r.inferred ThrownType s; | |
260 | } finally { | |
261 | log.popD iagnosticH andler(dia gHandler); | |
262 | } | |
263 | } | |
264 | ||
265 | /** | |
266 | * Def inite assi gnment sca n mode | |
267 | */ | |
268 | enum F lowKind { | |
269 | /* * | |
270 | * This is t he normal DA/DU anal ysis mode | |
271 | * / | |
272 | NO RMAL("var. might.alre ady.be.ass igned", fa lse), | |
273 | /* * | |
274 | * This is t he specula tive DA/DU analysis mode used to specula tively | |
275 | * derive as sertions w ithin loop bodies | |
276 | * / | |
277 | SP ECULATIVE_ LOOP("var. might.be.a ssigned.in .loop", tr ue); | |
278 | ||
279 | fi nal String errKey; | |
280 | fi nal boolea n isFinal; | |
281 | ||
282 | Fl owKind(Str ing errKey , boolean isFinal) { | |
283 | this.err Key = errK ey; | |
284 | this.isF inal = isF inal; | |
285 | } | |
286 | ||
287 | bo olean isFi nal() { | |
288 | return i sFinal; | |
289 | } | |
290 | } | |
291 | ||
292 | protec ted Flow(C ontext con text) { | |
293 | co ntext.put( flowKey, t his); | |
294 | na mes = Name s.instance (context); | |
295 | lo g = Log.in stance(con text); | |
296 | sy ms = Symta b.instance (context); | |
297 | ty pes = Type s.instance (context); | |
298 | ch k = Check. instance(c ontext); | |
299 | li nt = Lint. instance(c ontext); | |
300 | rs = Resolve .instance( context); | |
301 | di ags = JCDi agnostic.F actory.ins tance(cont ext); | |
302 | So urce sourc e = Source .instance( context); | |
303 | al lowImprove dRethrowAn alysis = s ource.allo wImprovedR ethrowAnal ysis(); | |
304 | al lowImprove dCatchAnal ysis = sou rce.allowI mprovedCat chAnalysis (); | |
305 | al lowEffecti velyFinalI nInnerClas ses = sour ce.allowEf fectivelyF inalInInne rClasses() ; | |
306 | en forceThisD otInit = s ource.enfo rceThisDot Init(); | |
307 | } | |
308 | ||
309 | /** | |
310 | * Bas e visitor class for all visito rs impleme nting data flow analy sis logic. | |
311 | * Thi s class de fine the s hared logi c for hand ling jumps (break/co ntinue sta tements). | |
312 | */ | |
313 | static abstract class Base Analyzer<P extends B aseAnalyze r.PendingE xit> exten ds TreeSca nner { | |
314 | ||
315 | en um JumpKin d { | |
316 | BREAK(JC Tree.Tag.B REAK) { | |
317 | @Ove rride | |
318 | JCTr ee getTarg et(JCTree tree) { | |
319 | return ((J CBreak)tre e).target; | |
320 | } | |
321 | }, | |
322 | CONTINUE (JCTree.Ta g.CONTINUE ) { | |
323 | @Ove rride | |
324 | JCTr ee getTarg et(JCTree tree) { | |
325 | return ((J CContinue) tree).targ et; | |
326 | } | |
327 | }; | |
328 | ||
329 | final JC Tree.Tag t reeTag; | |
330 | ||
331 | private JumpKind(T ag treeTag ) { | |
332 | this .treeTag = treeTag; | |
333 | } | |
334 | ||
335 | abstract JCTree ge tTarget(JC Tree tree) ; | |
336 | } | |
337 | ||
338 | /* * The curr ently pend ing exits that go fr om current inner blo cks | |
339 | * to an en closing bl ock, in so urce order . | |
340 | * / | |
341 | Li stBuffer<P > pendingE xits; | |
342 | ||
343 | /* * A pendin g exit. T hese are t he stateme nts return , break, a nd | |
344 | * continue . In addi tion, exce ption-thro wing expre ssions or | |
345 | * statemen ts are put here when not known to be cau ght. This | |
346 | * will typ ically res ult in an error unle ss it is w ithin a | |
347 | * try-fina lly whose finally bl ock cannot complete normally. | |
348 | * / | |
349 | st atic class PendingEx it { | |
350 | JCTree t ree; | |
351 | ||
352 | PendingE xit(JCTree tree) { | |
353 | this .tree = tr ee; | |
354 | } | |
355 | ||
356 | void res olveJump() { | |
357 | //do nothing | |
358 | } | |
359 | } | |
360 | ||
361 | ab stract voi d markDead (); | |
362 | ||
363 | /* * Record a n outward transfer o f control. */ | |
364 | vo id recordE xit(P pe) { | |
365 | pendingE xits.appen d(pe); | |
366 | markDead (); | |
367 | } | |
368 | ||
369 | /* * Resolve all jumps of this st atement. * / | |
370 | pr ivate bool ean resolv eJump(JCTr ee tree, | |
371 | ListBu ffer<P> ol dPendingEx its, | |
372 | JumpKi nd jk) { | |
373 | boolean resolved = false; | |
374 | List<P> exits = pe ndingExits .toList(); | |
375 | pendingE xits = old PendingExi ts; | |
376 | for (; e xits.nonEm pty(); exi ts = exits .tail) { | |
377 | P ex it = exits .head; | |
378 | if ( exit.tree. hasTag(jk. treeTag) & & | |
379 | jk.get Target(exi t.tree) == tree) { | |
380 | exit.resol veJump(); | |
381 | resolved = true; | |
382 | } el se { | |
383 | pendingExi ts.append( exit); | |
384 | } | |
385 | } | |
386 | return r esolved; | |
387 | } | |
388 | ||
389 | /* * Resolve all contin ues of thi s statemen t. */ | |
390 | bo olean reso lveContinu es(JCTree tree) { | |
391 | return r esolveJump (tree, new ListBuffe r<P>(), Ju mpKind.CON TINUE); | |
392 | } | |
393 | ||
394 | /* * Resolve all breaks of this s tatement. */ | |
395 | bo olean reso lveBreaks( JCTree tre e, ListBuf fer<P> old PendingExi ts) { | |
396 | return r esolveJump (tree, old PendingExi ts, JumpKi nd.BREAK); | |
397 | } | |
398 | ||
399 | @O verride | |
400 | pu blic void scan(JCTre e tree) { | |
401 | if (tree != null & & ( | |
402 | tree.type == null || | |
403 | tree.type != Type.st uckType)) { | |
404 | supe r.scan(tre e); | |
405 | } | |
406 | } | |
407 | } | |
408 | ||
409 | /** | |
410 | * Thi s pass imp lements th e first st ep of the dataflow a nalysis, n amely | |
411 | * the liveness analysis c heck. This checks th at every s tatement i s reachabl e. | |
412 | * The output of this anal ysis pass are used b y other an alyzers. T his analyz er | |
413 | * set s the 'fin allyCanCom pleteNorma lly' field in the JC Try class. | |
414 | */ | |
415 | class AliveAnaly zer extend s BaseAnal yzer<BaseA nalyzer.Pe ndingExit> { | |
416 | ||
417 | /* * A flag t hat indica tes whethe r the last statement could | |
418 | * complete normally. | |
419 | * / | |
420 | pr ivate bool ean alive; | |
421 | ||
422 | @O verride | |
423 | vo id markDea d() { | |
424 | alive = false; | |
425 | } | |
426 | ||
427 | /***** ********** ********** ********** ********** ********** ********** ******** | |
428 | * Vis itor metho ds for sta tements an d definiti ons | |
429 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
430 | ||
431 | /* * Analyze a definiti on. | |
432 | * / | |
433 | vo id scanDef (JCTree tr ee) { | |
434 | scanStat (tree); | |
435 | if (tree != null & & tree.has Tag(JCTree .Tag.BLOCK ) && !aliv e) { | |
436 | log. error(tree .pos(), | |
437 | "ini tializer.m ust.be.abl e.to.compl ete.normal ly"); | |
438 | } | |
439 | } | |
440 | ||
441 | /* * Analyze a statemen t. Check t hat statem ent is rea chable. | |
442 | * / | |
443 | vo id scanSta t(JCTree t ree) { | |
444 | if (!ali ve && tree != null) { | |
445 | log. error(tree .pos(), "u nreachable .stmt"); | |
446 | if ( !tree.hasT ag(SKIP)) alive = tr ue; | |
447 | } | |
448 | scan(tre e); | |
449 | } | |
450 | ||
451 | /* * Analyze list of st atements. | |
452 | * / | |
453 | vo id scanSta ts(List<? extends JC Statement> trees) { | |
454 | if (tree s != null) | |
455 | for (List<? ex tends JCSt atement> l = trees; l.nonEmpty (); l = l. tail) | |
456 | scanStat(l .head); | |
457 | } | |
458 | ||
459 | /* --------- --- Visito r methods for variou s sorts of trees --- ---------- */ | |
460 | ||
461 | pu blic void visitClass Def(JCClas sDecl tree ) { | |
462 | if (tree .sym == nu ll) return ; | |
463 | boolean alivePrev = alive; | |
464 | ListBuff er<Pending Exit> pend ingExitsPr ev = pendi ngExits; | |
465 | Lint lin tPrev = li nt; | |
466 | ||
467 | pendingE xits = new ListBuffe r<>(); | |
468 | lint = l int.augmen t(tree.sym ); | |
469 | ||
470 | try { | |
471 | // p rocess all the stati c initiali zers | |
472 | for (List<JCTr ee> l = tr ee.defs; l .nonEmpty( ); l = l.t ail) { | |
473 | if (!l.hea d.hasTag(M ETHODDEF) && | |
474 | (TreeI nfo.flags( l.head) & STATIC) != 0) { | |
475 | scanDe f(l.head); | |
476 | } | |
477 | } | |
478 | ||
479 | // p rocess all the insta nce initia lizers | |
480 | for (List<JCTr ee> l = tr ee.defs; l .nonEmpty( ); l = l.t ail) { | |
481 | if (!l.hea d.hasTag(M ETHODDEF) && | |
482 | (TreeI nfo.flags( l.head) & STATIC) == 0) { | |
483 | scanDe f(l.head); | |
484 | } | |
485 | } | |
486 | ||
487 | // p rocess all the metho ds | |
488 | for (List<JCTr ee> l = tr ee.defs; l .nonEmpty( ); l = l.t ail) { | |
489 | if (l.head .hasTag(ME THODDEF)) { | |
490 | scan(l .head); | |
491 | } | |
492 | } | |
493 | } finall y { | |
494 | pend ingExits = pendingEx itsPrev; | |
495 | aliv e = aliveP rev; | |
496 | lint = lintPre v; | |
497 | } | |
498 | } | |
499 | ||
500 | pu blic void visitMetho dDef(JCMet hodDecl tr ee) { | |
501 | if (tree .body == n ull) retur n; | |
502 | Lint lin tPrev = li nt; | |
503 | ||
504 | lint = l int.augmen t(tree.sym ); | |
505 | ||
506 | Assert.c heck(pendi ngExits.is Empty()); | |
507 | ||
508 | try { | |
509 | aliv e = true; | |
510 | scan Stat(tree. body); | |
511 | ||
512 | if ( alive && ! tree.sym.t ype.getRet urnType(). hasTag(VOI D)) | |
513 | log.error( TreeInfo.d iagEndPos( tree.body) , "missing .ret.stmt" ); | |
514 | ||
515 | List <PendingEx it> exits = pendingE xits.toLis t(); | |
516 | pend ingExits = new ListB uffer<>(); | |
517 | whil e (exits.n onEmpty()) { | |
518 | PendingExi t exit = e xits.head; | |
519 | exits = ex its.tail; | |
520 | Assert.che ck(exit.tr ee.hasTag( RETURN)); | |
521 | } | |
522 | } finall y { | |
523 | lint = lintPre v; | |
524 | } | |
525 | } | |
526 | ||
527 | pu blic void visitVarDe f(JCVariab leDecl tre e) { | |
528 | if (tree .init != n ull) { | |
529 | Lint lintPrev = lint; | |
530 | lint = lint.au gment(tree .sym); | |
531 | try{ | |
532 | scan(tree. init); | |
533 | } fi nally { | |
534 | lint = lin tPrev; | |
535 | } | |
536 | } | |
537 | } | |
538 | ||
539 | pu blic void visitBlock (JCBlock t ree) { | |
540 | scanStat s(tree.sta ts); | |
541 | } | |
542 | ||
543 | pu blic void visitDoLoo p(JCDoWhil eLoop tree ) { | |
544 | ListBuff er<Pending Exit> prev PendingExi ts = pendi ngExits; | |
545 | pendingE xits = new ListBuffe r<>(); | |
546 | scanStat (tree.body ); | |
547 | alive |= resolveCo ntinues(tr ee); | |
548 | scan(tre e.cond); | |
549 | alive = alive && ! tree.cond. type.isTru e(); | |
550 | alive |= resolveBr eaks(tree, prevPendi ngExits); | |
551 | } | |
552 | ||
553 | pu blic void visitWhile Loop(JCWhi leLoop tre e) { | |
554 | ListBuff er<Pending Exit> prev PendingExi ts = pendi ngExits; | |
555 | pendingE xits = new ListBuffe r<>(); | |
556 | scan(tre e.cond); | |
557 | alive = !tree.cond .type.isFa lse(); | |
558 | scanStat (tree.body ); | |
559 | alive |= resolveCo ntinues(tr ee); | |
560 | alive = resolveBre aks(tree, prevPendin gExits) || | |
561 | !tre e.cond.typ e.isTrue() ; | |
562 | } | |
563 | ||
564 | pu blic void visitForLo op(JCForLo op tree) { | |
565 | ListBuff er<Pending Exit> prev PendingExi ts = pendi ngExits; | |
566 | scanStat s(tree.ini t); | |
567 | pendingE xits = new ListBuffe r<>(); | |
568 | if (tree .cond != n ull) { | |
569 | scan (tree.cond ); | |
570 | aliv e = !tree. cond.type. isFalse(); | |
571 | } else { | |
572 | aliv e = true; | |
573 | } | |
574 | scanStat (tree.body ); | |
575 | alive |= resolveCo ntinues(tr ee); | |
576 | scan(tre e.step); | |
577 | alive = resolveBre aks(tree, prevPendin gExits) || | |
578 | tree .cond != n ull && !tr ee.cond.ty pe.isTrue( ); | |
579 | } | |
580 | ||
581 | pu blic void visitForea chLoop(JCE nhancedFor Loop tree) { | |
582 | visitVar Def(tree.v ar); | |
583 | ListBuff er<Pending Exit> prev PendingExi ts = pendi ngExits; | |
584 | scan(tre e.expr); | |
585 | pendingE xits = new ListBuffe r<>(); | |
586 | scanStat (tree.body ); | |
587 | alive |= resolveCo ntinues(tr ee); | |
588 | resolveB reaks(tree , prevPend ingExits); | |
589 | alive = true; | |
590 | } | |
591 | ||
592 | pu blic void visitLabel led(JCLabe ledStateme nt tree) { | |
593 | ListBuff er<Pending Exit> prev PendingExi ts = pendi ngExits; | |
594 | pendingE xits = new ListBuffe r<>(); | |
595 | scanStat (tree.body ); | |
596 | alive |= resolveBr eaks(tree, prevPendi ngExits); | |
597 | } | |
598 | ||
599 | pu blic void visitSwitc h(JCSwitch tree) { | |
600 | ListBuff er<Pending Exit> prev PendingExi ts = pendi ngExits; | |
601 | pendingE xits = new ListBuffe r<>(); | |
602 | scan(tre e.selector ); | |
603 | boolean hasDefault = false; | |
604 | for (Lis t<JCCase> l = tree.c ases; l.no nEmpty(); l = l.tail ) { | |
605 | aliv e = true; | |
606 | JCCa se c = l.h ead; | |
607 | if ( c.pat == n ull) | |
608 | hasDefault = true; | |
609 | else | |
610 | scan(c.pat ); | |
611 | scan Stats(c.st ats); | |
612 | // W arn about fall-throu gh if lint switch fa llthrough enabled. | |
613 | if ( alive && | |
614 | lint.isEna bled(Lint. LintCatego ry.FALLTHR OUGH) && | |
615 | c.stats.no nEmpty() & & l.tail.n onEmpty()) | |
616 | log.warnin g(Lint.Lin tCategory. FALLTHROUG H, | |
617 | l.tail.h ead.pos(), | |
618 | "possibl e.fall-thr ough.into. case"); | |
619 | } | |
620 | if (!has Default) { | |
621 | aliv e = true; | |
622 | } | |
623 | alive |= resolveBr eaks(tree, prevPendi ngExits); | |
624 | } | |
625 | ||
626 | pu blic void visitTry(J CTry tree) { | |
627 | ListBuff er<Pending Exit> prev PendingExi ts = pendi ngExits; | |
628 | pendingE xits = new ListBuffe r<>(); | |
629 | for (JCT ree resour ce : tree. resources) { | |
630 | if ( resource i nstanceof JCVariable Decl) { | |
631 | JCVariable Decl vdecl = (JCVari ableDecl) resource; | |
632 | visitVarDe f(vdecl); | |
633 | } el se if (res ource inst anceof JCE xpression) { | |
634 | scan((JCEx pression) resource); | |
635 | } el se { | |
636 | throw new AssertionE rror(tree) ; // pars er error | |
637 | } | |
638 | } | |
639 | ||
640 | scanStat (tree.body ); | |
641 | boolean aliveEnd = alive; | |
642 | ||
643 | for (Lis t<JCCatch> l = tree. catchers; l.nonEmpty (); l = l. tail) { | |
644 | aliv e = true; | |
645 | JCVa riableDecl param = l .head.para m; | |
646 | scan (param); | |
647 | scan Stat(l.hea d.body); | |
648 | aliv eEnd |= al ive; | |
649 | } | |
650 | if (tree .finalizer != null) { | |
651 | List Buffer<Pen dingExit> exits = pe ndingExits ; | |
652 | pend ingExits = prevPendi ngExits; | |
653 | aliv e = true; | |
654 | scan Stat(tree. finalizer) ; | |
655 | tree .finallyCa nCompleteN ormally = alive; | |
656 | if ( !alive) { | |
657 | if (lint.i sEnabled(L int.LintCa tegory.FIN ALLY)) { | |
658 | log.wa rning(Lint .LintCateg ory.FINALL Y, | |
659 | TreeInfo .diagEndPo s(tree.fin alizer), | |
660 | "finally .cannot.co mplete"); | |
661 | } | |
662 | } el se { | |
663 | while (exi ts.nonEmpt y()) { | |
664 | pendin gExits.app end(exits. next()); | |
665 | } | |
666 | alive = al iveEnd; | |
667 | } | |
668 | } else { | |
669 | aliv e = aliveE nd; | |
670 | List Buffer<Pen dingExit> exits = pe ndingExits ; | |
671 | pend ingExits = prevPendi ngExits; | |
672 | whil e (exits.n onEmpty()) pendingEx its.append (exits.nex t()); | |
673 | } | |
674 | } | |
675 | ||
676 | @O verride | |
677 | pu blic void visitIf(JC If tree) { | |
678 | scan(tre e.cond); | |
679 | scanStat (tree.then part); | |
680 | if (tree .elsepart != null) { | |
681 | bool ean aliveA fterThen = alive; | |
682 | aliv e = true; | |
683 | scan Stat(tree. elsepart); | |
684 | aliv e = alive | aliveAft erThen; | |
685 | } else { | |
686 | aliv e = true; | |
687 | } | |
688 | } | |
689 | ||
690 | pu blic void visitBreak (JCBreak t ree) { | |
691 | recordEx it(new Pen dingExit(t ree)); | |
692 | } | |
693 | ||
694 | pu blic void visitConti nue(JCCont inue tree) { | |
695 | recordEx it(new Pen dingExit(t ree)); | |
696 | } | |
697 | ||
698 | pu blic void visitRetur n(JCReturn tree) { | |
699 | scan(tre e.expr); | |
700 | recordEx it(new Pen dingExit(t ree)); | |
701 | } | |
702 | ||
703 | pu blic void visitThrow (JCThrow t ree) { | |
704 | scan(tre e.expr); | |
705 | markDead (); | |
706 | } | |
707 | ||
708 | pu blic void visitApply (JCMethodI nvocation tree) { | |
709 | scan(tre e.meth); | |
710 | scan(tre e.args); | |
711 | } | |
712 | ||
713 | pu blic void visitNewCl ass(JCNewC lass tree) { | |
714 | scan(tre e.encl); | |
715 | scan(tre e.args); | |
716 | if (tree .def != nu ll) { | |
717 | scan (tree.def) ; | |
718 | } | |
719 | } | |
720 | ||
721 | @O verride | |
722 | pu blic void visitLambd a(JCLambda tree) { | |
723 | if (tree .type != n ull && | |
724 | tree.type. isErroneou s()) { | |
725 | retu rn; | |
726 | } | |
727 | ||
728 | ListBuff er<Pending Exit> prev Pending = pendingExi ts; | |
729 | boolean prevAlive = alive; | |
730 | try { | |
731 | pend ingExits = new ListB uffer<>(); | |
732 | aliv e = true; | |
733 | scan Stat(tree. body); | |
734 | tree .canComple teNormally = alive; | |
735 | } | |
736 | finally { | |
737 | pend ingExits = prevPendi ng; | |
738 | aliv e = prevAl ive; | |
739 | } | |
740 | } | |
741 | ||
742 | pu blic void visitTopLe vel(JCComp ilationUni t tree) { | |
743 | // Do no thing for TopLevel s ince each class is v isited ind ividually | |
744 | } | |
745 | ||
746 | /***** ********** ********** ********** ********** ********** ********** ********* | |
747 | * mai n method | |
748 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
749 | ||
750 | /* * Perform definite a ssignment/ unassignme nt analysi s on a tre e. | |
751 | * / | |
752 | pu blic void analyzeTre e(Env<Attr Context> e nv, TreeMa ker make) { | |
753 | analyzeT ree(env, e nv.tree, m ake); | |
754 | } | |
755 | pu blic void analyzeTre e(Env<Attr Context> e nv, JCTree tree, Tre eMaker mak e) { | |
756 | try { | |
757 | attr Env = env; | |
758 | Flow .this.make = make; | |
759 | pend ingExits = new ListB uffer<>(); | |
760 | aliv e = true; | |
761 | scan (tree); | |
762 | } finall y { | |
763 | pend ingExits = null; | |
764 | Flow .this.make = null; | |
765 | } | |
766 | } | |
767 | } | |
768 | ||
769 | /** | |
770 | * Thi s pass imp lements th e second s tep of the dataflow analysis, namely | |
771 | * the exception analysis. This is t o ensure t hat every checked ex ception th at is | |
772 | * thr own is dec lared or c aught. The analyzer uses some info that has been s et by | |
773 | * the livelines s analyzer . | |
774 | */ | |
775 | class FlowAnalyz er extends BaseAnaly zer<FlowAn alyzer.Flo wPendingEx it> { | |
776 | ||
777 | /* * A flag t hat indica tes whethe r the last statement could | |
778 | * complete normally. | |
779 | * / | |
780 | Ha shMap<Symb ol, List<T ype>> prec iseRethrow Types; | |
781 | ||
782 | /* * The curr ent class being defi ned. | |
783 | * / | |
784 | JC ClassDecl classDef; | |
785 | ||
786 | /* * The list of possib ly thrown declarable exception s. | |
787 | * / | |
788 | Li st<Type> t hrown; | |
789 | ||
790 | /* * The list of except ions that are either caught or declared to be | |
791 | * thrown. | |
792 | * / | |
793 | Li st<Type> c aught; | |
794 | ||
795 | cl ass FlowPe ndingExit extends Ba seAnalyzer .PendingEx it { | |
796 | ||
797 | Type thr own; | |
798 | ||
799 | FlowPend ingExit(JC Tree tree, Type thro wn) { | |
800 | supe r(tree); | |
801 | this .thrown = thrown; | |
802 | } | |
803 | } | |
804 | ||
805 | @O verride | |
806 | vo id markDea d() { | |
807 | //do not hing | |
808 | } | |
809 | ||
810 | /* ---------- ---------- Exception s -------- ---------- ----*/ | |
811 | ||
812 | /* * Complain that pend ing except ions are n ot caught. | |
813 | * / | |
814 | vo id errorUn caught() { | |
815 | for (Flo wPendingEx it exit = pendingExi ts.next(); | |
816 | exi t != null; | |
817 | exi t = pendin gExits.nex t()) { | |
818 | if ( classDef ! = null && | |
819 | classDef.p os == exit .tree.pos) { | |
820 | log.error( exit.tree. pos(), | |
821 | "u nreported. exception. default.co nstructor" , | |
822 | ex it.thrown) ; | |
823 | } else if (exit.tree .hasTag(
|
|
824 | ((JCVa riableDecl )exit.tree ).sym.isRe sourceVari able()) { | |
825 | log.error( exit.tree. pos(), | |
826 | "u nreported. exception. implicit.c lose", | |
827 | ex it.thrown, | |
828 | (( JCVariable Decl)exit. tree).sym. name); | |
829 | } el se { | |
830 | log.error( exit.tree. pos(), | |
831 | "u nreported. exception. need.to.ca tch.or.thr ow", | |
832 | ex it.thrown) ; | |
833 | } | |
834 | } | |
835 | } | |
836 | ||
837 | /* * Record t hat except ion is pot entially t hrown and check that it | |
838 | * is caugh t. | |
839 | * / | |
840 | vo id markThr own(JCTree tree, Typ e exc) { | |
841 | if (!chk .isUncheck ed(tree.po s(), exc)) { | |
842 | if ( !chk.isHan dled(exc, caught)) { | |
843 | pendingExi ts.append( new FlowPe ndingExit( tree, exc) ); | |
844 | } | |
845 | thro wn = chk.i ncl(exc, t hrown); | |
846 | } | |
847 | } | |
848 | ||
849 | /***** ********** ********** ********** ********** ********** ********** ******** | |
850 | * Vis itor metho ds for sta tements an d definiti ons | |
851 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
852 | ||
853 | /* --------- --- Visito r methods for variou s sorts of trees --- ---------- */ | |
854 | ||
855 | pu blic void visitClass Def(JCClas sDecl tree ) { | |
856 | if (tree .sym == nu ll) return ; | |
857 | ||
858 | JCClassD ecl classD efPrev = c lassDef; | |
859 | List<Typ e> thrownP rev = thro wn; | |
860 | List<Typ e> caughtP rev = caug ht; | |
861 | ListBuff er<FlowPen dingExit> pendingExi tsPrev = p endingExit s; | |
862 | Lint lin tPrev = li nt; | |
863 | ||
864 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
865 | if (tree .name != n ames.empty ) { | |
866 | caug ht = List. nil(); | |
867 | } | |
868 | classDef = tree; | |
869 | thrown = List.nil( ); | |
870 | lint = l int.augmen t(tree.sym ); | |
871 | ||
872 | try { | |
873 | // p rocess all the stati c initiali zers | |
874 | for (List<JCTr ee> l = tr ee.defs; l .nonEmpty( ); l = l.t ail) { | |
875 | if (!l.hea d.hasTag(M ETHODDEF) && | |
876 | (TreeI nfo.flags( l.head) & STATIC) != 0) { | |
877 | scan(l .head); | |
878 | errorU ncaught(); | |
879 | } | |
880 | } | |
881 | ||
882 | // a dd interse ction of a ll thrown clauses of initial c onstructor s | |
883 | // t o set of c aught exce ptions, un less class is anonym ous. | |
884 | if ( tree.name != names.e mpty) { | |
885 | boolean fi rstConstru ctor = tru e; | |
886 | for (List< JCTree> l = tree.def s; l.nonEm pty(); l = l.tail) { | |
887 | if (Tr eeInfo.isI nitialCons tructor(l. head)) { | |
888 | Li st<Type> m thrown = | |
889 | ((JCMeth odDecl) l. head).sym. type.getTh rownTypes( ); | |
890 | if (firstCon structor) { | |
891 | caught = mthrown; | |
892 | firstCon structor = false; | |
893 | } else { | |
894 | caught = chk.inter sect(mthro wn, caught ); | |
895 | } | |
896 | } | |
897 | } | |
898 | } | |
899 | ||
900 | // p rocess all the insta nce initia lizers | |
901 | for (List<JCTr ee> l = tr ee.defs; l .nonEmpty( ); l = l.t ail) { | |
902 | if (!l.hea d.hasTag(M ETHODDEF) && | |
903 | (TreeI nfo.flags( l.head) & STATIC) == 0) { | |
904 | scan(l .head); | |
905 | errorU ncaught(); | |
906 | } | |
907 | } | |
908 | ||
909 | // i n an anony mous class , add the set of thr own except ions to | |
910 | // t he throws clause of the synthe tic constr uctor and propagate | |
911 | // o utwards. | |
912 | // C hanging th e throws c lause on t he fly is okay here because | |
913 | // t he anonymo us constru ctor can't be invoke d anywhere else, | |
914 | // a nd its typ e hasn't b een cached . | |
915 | if ( tree.name == names.e mpty) { | |
916 | for (List< JCTree> l = tree.def s; l.nonEm pty(); l = l.tail) { | |
917 | if (Tr eeInfo.isI nitialCons tructor(l. head)) { | |
918 | JC MethodDecl mdef = (J CMethodDec l)l.head; | |
919 | md ef.thrown = make.Typ es(thrown) ; | |
920 | md ef.sym.typ e = types. createMeth odTypeWith Thrown(mde f.sym.type , thrown); | |
921 | } | |
922 | } | |
923 | thrownPrev = chk.uni on(thrown, thrownPre v); | |
924 | } | |
925 | ||
926 | // p rocess all the metho ds | |
927 | for (List<JCTr ee> l = tr ee.defs; l .nonEmpty( ); l = l.t ail) { | |
928 | if (l.head .hasTag(ME THODDEF)) { | |
929 | scan(l .head); | |
930 | errorU ncaught(); | |
931 | } | |
932 | } | |
933 | ||
934 | thro wn = throw nPrev; | |
935 | } finall y { | |
936 | pend ingExits = pendingEx itsPrev; | |
937 | caug ht = caugh tPrev; | |
938 | clas sDef = cla ssDefPrev; | |
939 | lint = lintPre v; | |
940 | } | |
941 | } | |
942 | ||
943 | pu blic void visitMetho dDef(JCMet hodDecl tr ee) { | |
944 | if (tree .body == n ull) retur n; | |
945 | ||
946 | List<Typ e> caughtP rev = caug ht; | |
947 | List<Typ e> mthrown = tree.sy m.type.get ThrownType s(); | |
948 | Lint lin tPrev = li nt; | |
949 | ||
950 | lint = l int.augmen t(tree.sym ); | |
951 | ||
952 | Assert.c heck(pendi ngExits.is Empty()); | |
953 | ||
954 | try { | |
955 | for (List<JCVa riableDecl > l = tree .params; l .nonEmpty( ); l = l.t ail) { | |
956 | JCVariable Decl def = l.head; | |
957 | scan(def); | |
958 | } | |
959 | if ( TreeInfo.i sInitialCo nstructor( tree)) | |
960 | caught = c hk.union(c aught, mth rown); | |
961 | else if ((tree .sym.flags () & (BLOC K | STATIC )) != BLOC K) | |
962 | caught = m thrown; | |
963 | // e lse we are in an ins tance init ializer bl ock; | |
964 | // l eave caugh t unchange d. | |
965 | ||
966 | scan (tree.body ); | |
967 | ||
968 | List <FlowPendi ngExit> ex its = pend ingExits.t oList(); | |
969 | pend ingExits = new ListB uffer<Flow PendingExi t>(); | |
970 | whil e (exits.n onEmpty()) { | |
971 | FlowPendin gExit exit = exits.h ead; | |
972 | exits = ex its.tail; | |
973 | if (exit.t hrown == n ull) { | |
974 | Assert .check(exi t.tree.has Tag(RETURN )); | |
975 | } else { | |
976 | // unc aught thro ws will be reported later | |
977 | pendin gExits.app end(exit); | |
978 | } | |
979 | } | |
980 | } finall y { | |
981 | caug ht = caugh tPrev; | |
982 | lint = lintPre v; | |
983 | } | |
984 | } | |
985 | ||
986 | pu blic void visitVarDe f(JCVariab leDecl tre e) { | |
987 | if (tree .init != n ull) { | |
988 | Lint lintPrev = lint; | |
989 | lint = lint.au gment(tree .sym); | |
990 | try{ | |
991 | scan(tree. init); | |
992 | } fi nally { | |
993 | lint = lin tPrev; | |
994 | } | |
995 | } | |
996 | } | |
997 | ||
998 | pu blic void visitBlock (JCBlock t ree) { | |
999 | scan(tre e.stats); | |
1000 | } | |
1001 | ||
1002 | pu blic void visitDoLoo p(JCDoWhil eLoop tree ) { | |
1003 | ListBuff er<FlowPen dingExit> prevPendin gExits = p endingExit s; | |
1004 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
1005 | scan(tre e.body); | |
1006 | resolveC ontinues(t ree); | |
1007 | scan(tre e.cond); | |
1008 | resolveB reaks(tree , prevPend ingExits); | |
1009 | } | |
1010 | ||
1011 | pu blic void visitWhile Loop(JCWhi leLoop tre e) { | |
1012 | ListBuff er<FlowPen dingExit> prevPendin gExits = p endingExit s; | |
1013 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
1014 | scan(tre e.cond); | |
1015 | scan(tre e.body); | |
1016 | resolveC ontinues(t ree); | |
1017 | resolveB reaks(tree , prevPend ingExits); | |
1018 | } | |
1019 | ||
1020 | pu blic void visitForLo op(JCForLo op tree) { | |
1021 | ListBuff er<FlowPen dingExit> prevPendin gExits = p endingExit s; | |
1022 | scan(tre e.init); | |
1023 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
1024 | if (tree .cond != n ull) { | |
1025 | scan (tree.cond ); | |
1026 | } | |
1027 | scan(tre e.body); | |
1028 | resolveC ontinues(t ree); | |
1029 | scan(tre e.step); | |
1030 | resolveB reaks(tree , prevPend ingExits); | |
1031 | } | |
1032 | ||
1033 | pu blic void visitForea chLoop(JCE nhancedFor Loop tree) { | |
1034 | visitVar Def(tree.v ar); | |
1035 | ListBuff er<FlowPen dingExit> prevPendin gExits = p endingExit s; | |
1036 | scan(tre e.expr); | |
1037 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
1038 | scan(tre e.body); | |
1039 | resolveC ontinues(t ree); | |
1040 | resolveB reaks(tree , prevPend ingExits); | |
1041 | } | |
1042 | ||
1043 | pu blic void visitLabel led(JCLabe ledStateme nt tree) { | |
1044 | ListBuff er<FlowPen dingExit> prevPendin gExits = p endingExit s; | |
1045 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
1046 | scan(tre e.body); | |
1047 | resolveB reaks(tree , prevPend ingExits); | |
1048 | } | |
1049 | ||
1050 | pu blic void visitSwitc h(JCSwitch tree) { | |
1051 | ListBuff er<FlowPen dingExit> prevPendin gExits = p endingExit s; | |
1052 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
1053 | scan(tre e.selector ); | |
1054 | for (Lis t<JCCase> l = tree.c ases; l.no nEmpty(); l = l.tail ) { | |
1055 | JCCa se c = l.h ead; | |
1056 | if ( c.pat != n ull) { | |
1057 | scan(c.pat ); | |
1058 | } | |
1059 | scan (c.stats); | |
1060 | } | |
1061 | resolveB reaks(tree , prevPend ingExits); | |
1062 | } | |
1063 | ||
1064 | pu blic void visitTry(J CTry tree) { | |
1065 | List<Typ e> caughtP rev = caug ht; | |
1066 | List<Typ e> thrownP rev = thro wn; | |
1067 | thrown = List.nil( ); | |
1068 | for (Lis t<JCCatch> l = tree. catchers; l.nonEmpty (); l = l. tail) { | |
1069 | List <JCExpress ion> subCl auses = Tr eeInfo.isM ultiCatch( l.head) ? | |
1070 | ((JCTy peUnion)l. head.param .vartype). alternativ es : | |
1071 | List.o f(l.head.p aram.varty pe); | |
1072 | for (JCExpress ion ct : s ubClauses) { | |
1073 | caught = c hk.incl(ct .type, cau ght); | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | ListBuff er<FlowPen dingExit> prevPendin gExits = p endingExit s; | |
1078 | pendingE xits = new ListBuffe r<FlowPend ingExit>() ; | |
1079 | for (JCT ree resour ce : tree. resources) { | |
1080 | if ( resource i nstanceof JCVariable Decl) { | |
1081 | JCVariable Decl vdecl = (JCVari ableDecl) resource; | |
1082 | visitVarDe f(vdecl); | |
1083 | } el se if (res ource inst anceof JCE xpression) { | |
1084 | scan((JCEx pression) resource); | |
1085 | } el se { | |
1086 | throw new AssertionE rror(tree) ; // pars er error | |
1087 | } | |
1088 | } | |
1089 | for (JCT ree resour ce : tree. resources) { | |
1090 | List <Type> clo seableSupe rtypes = r esource.ty pe.isCompo und() ? | |
1091 | types.inte rfaces(res ource.type ).prepend( types.supe rtype(reso urce.type) ) : | |
1092 | List.of(re source.typ e); | |
1093 | for (Type sup : closeabl eSupertype s) { | |
1094 | if (types. asSuper(su p, syms.au toCloseabl eType.tsym ) != null) { | |
1095 | Symbol closeMeth od = rs.re solveQuali fiedMethod (tree, | |
1096 | attrEnv, | |
1097 | sup, | |
1098 | names.cl ose, | |
1099 | List.<Ty pe>nil(), | |
1100 | List.<Ty pe>nil()); | |
1101 | Type m t = types. memberType (resource. type, clos eMethod); | |
1102 | if (cl oseMethod. kind == MT H) { | |
1103 | fo r (Type t : mt.getTh rownTypes( )) { | |
1104 | markThro wn(resourc e, t); | |
1105 | } | |
1106 | } | |
1107 | } | |
1108 | } | |
1109 | } | |
1110 | scan(tre e.body); | |
1111 | List<Typ e> thrownI nTry = all owImproved CatchAnaly sis ? | |
1112 | chk. union(thro wn, List.o f(syms.run timeExcept ionType, s yms.errorT ype)) : | |
1113 | thro wn; | |
1114 | thrown = thrownPre v; | |
1115 | caught = caughtPre v; | |
1116 | ||
1117 | List<Typ e> caughtI nTry = Lis t.nil(); | |
1118 | for (Lis t<JCCatch> l = tree. catchers; l.nonEmpty (); l = l. tail) { | |
1119 | JCVa riableDecl param = l .head.para m; | |
1120 | List <JCExpress ion> subCl auses = Tr eeInfo.isM ultiCatch( l.head) ? | |
1121 | ((JCTy peUnion)l. head.param .vartype). alternativ es : | |
1122 | List.o f(l.head.p aram.varty pe); | |
1123 | List <Type> cty pes = List .nil(); | |
1124 | List <Type> ret hrownTypes = chk.dif f(thrownIn Try, caugh tInTry); | |
1125 | for (JCExpress ion ct : s ubClauses) { | |
1126 | Type exc = ct.type; | |
1127 | if (exc != syms.unkn ownType) { | |
1128 | ctypes = ctypes. append(exc ); | |
1129 | if (ty pes.isSame Type(exc, syms.objec tType)) | |
1130 | co ntinue; | |
1131 | checkC aughtType( l.head.pos (), exc, t hrownInTry , caughtIn Try); | |
1132 | caught InTry = ch k.incl(exc , caughtIn Try); | |
1133 | } | |
1134 | } | |
1135 | scan (param); | |
1136 | prec iseRethrow Types.put( param.sym, chk.inter sect(ctype s, rethrow nTypes)); | |
1137 | scan (l.head.bo dy); | |
1138 | prec iseRethrow Types.remo ve(param.s ym); | |
1139 | } | |
1140 | if (tree .finalizer != null) { | |
1141 | List <Type> sav edThrown = thrown; | |
1142 | thro wn = List. nil(); | |
1143 | List Buffer<Flo wPendingEx it> exits = pendingE xits; | |
1144 | pend ingExits = prevPendi ngExits; | |
1145 | scan (tree.fina lizer); | |
1146 | if ( !tree.fina llyCanComp leteNormal ly) { | |
1147 | // discard exits and exception s from try and final ly | |
1148 | thrown = c hk.union(t hrown, thr ownPrev); | |
1149 | } el se { | |
1150 | thrown = c hk.union(t hrown, chk .diff(thro wnInTry, c aughtInTry )); | |
1151 | thrown = c hk.union(t hrown, sav edThrown); | |
1152 | // FIX: th is doesn't preserve source ord er of exit s in catch | |
1153 | // versus finally! | |
1154 | while (exi ts.nonEmpt y()) { | |
1155 | pendin gExits.app end(exits. next()); | |
1156 | } | |
1157 | } | |
1158 | } else { | |
1159 | thro wn = chk.u nion(throw n, chk.dif f(thrownIn Try, caugh tInTry)); | |
1160 | List Buffer<Flo wPendingEx it> exits = pendingE xits; | |
1161 | pend ingExits = prevPendi ngExits; | |
1162 | whil e (exits.n onEmpty()) pendingEx its.append (exits.nex t()); | |
1163 | } | |
1164 | } | |
1165 | ||
1166 | @O verride | |
1167 | pu blic void visitIf(JC If tree) { | |
1168 | scan(tre e.cond); | |
1169 | scan(tre e.thenpart ); | |
1170 | if (tree .elsepart != null) { | |
1171 | scan (tree.else part); | |
1172 | } | |
1173 | } | |
1174 | ||
1175 | vo id checkCa ughtType(D iagnosticP osition po s, Type ex c, List<Ty pe> thrown InTry, Lis t<Type> ca ughtInTry) { | |
1176 | if (chk. subset(exc , caughtIn Try)) { | |
1177 | log. error(pos, "except.a lready.cau ght", exc) ; | |
1178 | } else i f (!chk.is Unchecked( pos, exc) && | |
1179 | !isExcepti onOrThrowa ble(exc) & & | |
1180 | !chk.inter sects(exc, thrownInT ry)) { | |
1181 | log. error(pos, "except.n ever.throw n.in.try", exc); | |
1182 | } else i f (allowIm provedCatc hAnalysis) { | |
1183 | List <Type> cat chableThro wnTypes = chk.inters ect(List.o f(exc), th rownInTry) ; | |
1184 | // ' catchableT hrownTypes ' cannnot possibly b e empty - if 'exc' w as an | |
1185 | // u nchecked e xception, the result list woul d not be e mpty, as t he augment ed | |
1186 | // t hrown set includes { RuntimeEx ception, E rror }; if 'exc' was a checked | |
1187 | // e xception, that would have been covered i n the bran ch above | |
1188 | if ( chk.diff(c atchableTh rownTypes, caughtInT ry).isEmpt y() && | |
1189 | !isExc eptionOrTh rowable(ex c)) { | |
1190 | String key = catchab leThrownTy pes.length () == 1 ? | |
1191 | "u nreachable .catch" : | |
1192 | "u nreachable .catch.1"; | |
1193 | log.warnin g(pos, key , catchabl eThrownTyp es); | |
1194 | } | |
1195 | } | |
1196 | } | |
1197 | // where | |
1198 | private boolean is ExceptionO rThrowable (Type exc) { | |
1199 | retu rn exc.tsy m == syms. throwableT ype.tsym | | | |
1200 | exc.tsym = = syms.exc eptionType .tsym; | |
1201 | } | |
1202 | ||
1203 | pu blic void visitBreak (JCBreak t ree) { | |
1204 | recordEx it(new Flo wPendingEx it(tree, n ull)); | |
1205 | } | |
1206 | ||
1207 | pu blic void visitConti nue(JCCont inue tree) { | |
1208 | recordEx it(new Flo wPendingEx it(tree, n ull)); | |
1209 | } | |
1210 | ||
1211 | pu blic void visitRetur n(JCReturn tree) { | |
1212 | scan(tre e.expr); | |
1213 | recordEx it(new Flo wPendingEx it(tree, n ull)); | |
1214 | } | |
1215 | ||
1216 | pu blic void visitThrow (JCThrow t ree) { | |
1217 | scan(tre e.expr); | |
1218 | Symbol s ym = TreeI nfo.symbol (tree.expr ); | |
1219 | if (sym != null && | |
1220 | sym. kind == VA R && | |
1221 | (sym .flags() & (FINAL | EFFECTIVEL Y_FINAL)) != 0 && | |
1222 | prec iseRethrow Types.get( sym) != nu ll && | |
1223 | allo wImprovedR ethrowAnal ysis) { | |
1224 | for (Type t : preciseRet hrowTypes. get(sym)) { | |
1225 | markThrown (tree, t); | |
1226 | } | |
1227 | } | |
1228 | else { | |
1229 | mark Thrown(tre e, tree.ex pr.type); | |
1230 | } | |
1231 | markDead (); | |
1232 | } | |
1233 | ||
1234 | pu blic void visitApply (JCMethodI nvocation tree) { | |
1235 | scan(tre e.meth); | |
1236 | scan(tre e.args); | |
1237 | for (Lis t<Type> l = tree.met h.type.get ThrownType s(); l.non Empty(); l = l.tail) | |
1238 | mark Thrown(tre e, l.head) ; | |
1239 | } | |
1240 | ||
1241 | pu blic void visitNewCl ass(JCNewC lass tree) { | |
1242 | scan(tre e.encl); | |
1243 | scan(tre e.args); | |
1244 | // scan(t ree.def); | |
1245 | for (Lis t<Type> l = tree.con structorTy pe.getThro wnTypes(); | |
1246 | l.n onEmpty(); | |
1247 | l = l.tail) { | |
1248 | mark Thrown(tre e, l.head) ; | |
1249 | } | |
1250 | List<Typ e> caughtP rev = caug ht; | |
1251 | try { | |
1252 | // I f the new class expr ession def ines an an onymous cl ass, | |
1253 | // a nalysis of the anony mous const ructor may encounter thrown | |
1254 | // t ypes which are unsub stituted t ype variab les. | |
1255 | // H owever, si nce the co nstructor' s actual t hrown type s have | |
1256 | // a lready bee n marked a s thrown, it is safe to simply include | |
1257 | // e ach of the construct or's forma l thrown t ypes in th e set of | |
1258 | // ' caught/dec lared to b e thrown' types, for the durat ion of | |
1259 | // t he class d ef analysi s. | |
1260 | if ( tree.def ! = null) | |
1261 | for (List< Type> l = tree.const ructor.typ e.getThrow nTypes(); | |
1262 | l.non Empty(); | |
1263 | l = l .tail) { | |
1264 | caught = chk.inc l(l.head, caught); | |
1265 | } | |
1266 | scan (tree.def) ; | |
1267 | } | |
1268 | finally { | |
1269 | caug ht = caugh tPrev; | |
1270 | } | |
1271 | } | |
1272 | ||
1273 | @O verride | |
1274 | pu blic void visitLambd a(JCLambda tree) { | |
1275 | if (tree .type != n ull && | |
1276 | tree.type. isErroneou s()) { | |
1277 | retu rn; | |
1278 | } | |
1279 | List<Typ e> prevCau ght = caug ht; | |
1280 | List<Typ e> prevThr own = thro wn; | |
1281 | ListBuff er<FlowPen dingExit> prevPendin g = pendin gExits; | |
1282 | try { | |
1283 | pend ingExits = new ListB uffer<>(); | |
1284 | caug ht = tree. getDescrip torType(ty pes).getTh rownTypes( ); | |
1285 | thro wn = List. nil(); | |
1286 | scan (tree.body ); | |
1287 | List <FlowPendi ngExit> ex its = pend ingExits.t oList(); | |
1288 | pend ingExits = new ListB uffer<Flow PendingExi t>(); | |
1289 | whil e (exits.n onEmpty()) { | |
1290 | FlowPendin gExit exit = exits.h ead; | |
1291 | exits = ex its.tail; | |
1292 | if (exit.t hrown == n ull) { | |
1293 | Assert .check(exi t.tree.has Tag(RETURN )); | |
1294 | } else { | |
1295 | // unc aught thro ws will be reported later | |
1296 | pendin gExits.app end(exit); | |
1297 | } | |
1298 | } | |
1299 | ||
1300 | erro rUncaught( ); | |
1301 | } finall y { | |
1302 | pend ingExits = prevPendi ng; | |
1303 | caug ht = prevC aught; | |
1304 | thro wn = prevT hrown; | |
1305 | } | |
1306 | } | |
1307 | ||
1308 | pu blic void visitTopLe vel(JCComp ilationUni t tree) { | |
1309 | // Do no thing for TopLevel s ince each class is v isited ind ividually | |
1310 | } | |
1311 | ||
1312 | /***** ********** ********** ********** ********** ********** ********** ********* | |
1313 | * mai n method | |
1314 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
1315 | ||
1316 | /* * Perform definite a ssignment/ unassignme nt analysi s on a tre e. | |
1317 | * / | |
1318 | pu blic void analyzeTre e(Env<Attr Context> e nv, TreeMa ker make) { | |
1319 | analyzeT ree(env, e nv.tree, m ake); | |
1320 | } | |
1321 | pu blic void analyzeTre e(Env<Attr Context> e nv, JCTree tree, Tre eMaker mak e) { | |
1322 | try { | |
1323 | attr Env = env; | |
1324 | Flow .this.make = make; | |
1325 | pend ingExits = new ListB uffer<Flow PendingExi t>(); | |
1326 | prec iseRethrow Types = ne w HashMap< Symbol, Li st<Type>>( ); | |
1327 | this .thrown = this.caugh t = null; | |
1328 | this .classDef = null; | |
1329 | scan (tree); | |
1330 | } finall y { | |
1331 | pend ingExits = null; | |
1332 | Flow .this.make = null; | |
1333 | this .thrown = this.caugh t = null; | |
1334 | this .classDef = null; | |
1335 | } | |
1336 | } | |
1337 | } | |
1338 | ||
1339 | /** | |
1340 | * Spe cialized p ass that p erforms in ference of thrown ty pes for la mbdas. | |
1341 | */ | |
1342 | class LambdaFlow Analyzer e xtends Flo wAnalyzer { | |
1343 | Li st<Type> i nferredThr ownTypes; | |
1344 | bo olean inLa mbda; | |
1345 | @O verride | |
1346 | pu blic void visitLambd a(JCLambda tree) { | |
1347 | if ((tre e.type != null && | |
1348 | tree.type. isErroneou s()) || in Lambda) { | |
1349 | retu rn; | |
1350 | } | |
1351 | List<Typ e> prevCau ght = caug ht; | |
1352 | List<Typ e> prevThr own = thro wn; | |
1353 | ListBuff er<FlowPen dingExit> prevPendin g = pendin gExits; | |
1354 | inLambda = true; | |
1355 | try { | |
1356 | pend ingExits = new ListB uffer<>(); | |
1357 | caug ht = List. of(syms.th rowableTyp e); | |
1358 | thro wn = List. nil(); | |
1359 | scan (tree.body ); | |
1360 | infe rredThrown Types = th rown; | |
1361 | } finall y { | |
1362 | pend ingExits = prevPendi ng; | |
1363 | caug ht = prevC aught; | |
1364 | thro wn = prevT hrown; | |
1365 | inLa mbda = fal se; | |
1366 | } | |
1367 | } | |
1368 | @O verride | |
1369 | pu blic void visitClass Def(JCClas sDecl tree ) { | |
1370 | //skip | |
1371 | } | |
1372 | } | |
1373 | ||
1374 | /** | |
1375 | * Thi s pass imp lements (i ) definite assignmen t analysis , which en sures that | |
1376 | * eac h variable is assign ed when us ed and (ii ) definite unassignm ent analys is, | |
1377 | * whi ch ensures that no f inal varia ble is ass igned more than once . This vis itor | |
1378 | * dep ends on th e results of the liv eliness an alyzer. Th is pass is also used to mark | |
1379 | * eff ectively-f inal local variables /parameter s. | |
1380 | */ | |
1381 | ||
1382 | public class Ass ignAnalyze r extends BaseAnalyz er<AssignA nalyzer.As signPendin gExit> { | |
1383 | /* * The set of definit ely assign ed variabl es. | |
1384 | * / | |
1385 | fi nal Bits i nits; | |
1386 | ||
1387 | /* * The set of definit ely unassi gned varia bles. | |
1388 | * / | |
1389 | fi nal Bits u ninits; | |
1390 | ||
1391 | /* * The set of variabl es that ar e definite ly unassig ned everyw here | |
1392 | * in curre nt try blo ck. This v ariable is maintaine d lazily; it is | |
1393 | * updated only when something gets remov ed from un inits, | |
1394 | * typicall y by being assigned in reachab le code. To obtain the | |
1395 | * correct set of var iables whi ch are def initely un assigned | |
1396 | * anywhere in curren t try bloc k, interse ct uninits Try and | |
1397 | * uninits. | |
1398 | * / | |
1399 | fi nal Bits u ninitsTry; | |
1400 | ||
1401 | /* * When ana lyzing a c ondition, inits and uninits ar e null. | |
1402 | * Instead we have: | |
1403 | * / | |
1404 | fi nal Bits i nitsWhenTr ue; | |
1405 | fi nal Bits i nitsWhenFa lse; | |
1406 | fi nal Bits u ninitsWhen True; | |
1407 | fi nal Bits u ninitsWhen False; | |
1408 | ||
1409 | /* * A mappin g from add resses to variable s ymbols. | |
1410 | * / | |
1411 | pr otected JC VariableDe cl[] varde cls; | |
1412 | ||
1413 | /* * The curr ent class being defi ned. | |
1414 | * / | |
1415 | JC ClassDecl classDef; | |
1416 | ||
1417 | /* * The firs t variable sequence number in this class definitio n. | |
1418 | * / | |
1419 | in t firstadr ; | |
1420 | ||
1421 | /* * The next available variable sequence n umber. | |
1422 | * / | |
1423 | pr otected in t nextadr; | |
1424 | ||
1425 | /* * The firs t variable sequence number in a block th at can ret urn. | |
1426 | * / | |
1427 | pr otected in t returnad r; | |
1428 | ||
1429 | /* * The list of unrefe renced aut omatic res ources. | |
1430 | * / | |
1431 | Sc ope unrefd Resources; | |
1432 | ||
1433 | /* * Modified when proc essing a l oop body t he second time for D U analysis . */ | |
1434 | Fl owKind flo wKind = Fl owKind.NOR MAL; | |
1435 | ||
1436 | /* * The star ting posit ion of the analyzed tree */ | |
1437 | in t startPos ; | |
1438 | ||
1439 | pu blic class AssignPen dingExit e xtends Bas eAnalyzer. PendingExi t { | |
1440 | ||
1441 | final Bi ts inits; | |
1442 | final Bi ts uninits ; | |
1443 | final Bi ts exit_in its = new Bits(true) ; | |
1444 | final Bi ts exit_un inits = ne w Bits(tru e); | |
1445 | ||
1446 | public A ssignPendi ngExit(JCT ree tree, final Bits inits, fi nal Bits u ninits) { | |
1447 | supe r(tree); | |
1448 | this .inits = i nits; | |
1449 | this .uninits = uninits; | |
1450 | this .exit_init s.assign(i nits); | |
1451 | this .exit_unin its.assign (uninits); | |
1452 | } | |
1453 | ||
1454 | @Overrid e | |
1455 | void res olveJump() { | |
1456 | init s.andSet(e xit_inits) ; | |
1457 | unin its.andSet (exit_unin its); | |
1458 | } | |
1459 | } | |
1460 | ||
1461 | pu blic Assig nAnalyzer( ) { | |
1462 | this.ini ts = new B its(); | |
1463 | uninits = new Bits (); | |
1464 | uninitsT ry = new B its(); | |
1465 | initsWhe nTrue = ne w Bits(tru e); | |
1466 | initsWhe nFalse = n ew Bits(tr ue); | |
1467 | uninitsW henTrue = new Bits(t rue); | |
1468 | uninitsW henFalse = new Bits( true); | |
1469 | } | |
1470 | ||
1471 | pr ivate bool ean isInit ialConstru ctor = fal se; | |
1472 | ||
1473 | @O verride | |
1474 | v oid markDe ad() { | |
1475 | if (!isI nitialCons tructor) { | |
1476 | init s.inclRang e(returnad r, nextadr ); | |
1477 | } else { | |
1478 | for (int addre ss = retur nadr; addr ess < next adr; addre ss++) { | |
1479 | if (!(isFi nalUniniti alizedStat icField(va rdecls[add ress].sym) )) { | |
1480 | inits. incl(addre ss); | |
1481 | } | |
1482 | } | |
1483 | } | |
1484 | uninits. inclRange( returnadr, nextadr); | |
1485 | } | |
1486 | ||
1487 | /* ---------- ---- Proce ssing vari ables ---- ---------- --------*/ | |
1488 | ||
1489 | /* * Do we ne ed to trac k init/uni nit state of this sy mbol? | |
1490 | * I.e. is symbol eit her a loca l or a bla nk final v ariable? | |
1491 | * / | |
1492 | pr otected bo olean trac kable(VarS ymbol sym) { | |
1493 | return | |
1494 | sym. pos >= sta rtPos && | |
1495 | ((sy m.owner.ki nd == MTH || | |
1496 | isFi nalUniniti alizedFiel d(sym))); | |
1497 | } | |
1498 | ||
1499 | bo olean isFi nalUniniti alizedFiel d(VarSymbo l sym) { | |
1500 | return s ym.owner.k ind == TYP && | |
1501 | ( (sym.flags () & (FINA L | HASINI T | PARAME TER)) == F INAL && | |
1502 | c lassDef.sy m.isEnclos edBy((Clas sSymbol)sy m.owner)); | |
1503 | } | |
1504 | ||
1505 | bo olean isFi nalUniniti alizedStat icField(Va rSymbol sy m) { | |
1506 | return i sFinalUnin itializedF ield(sym) && sym.isS tatic(); | |
1507 | } | |
1508 | ||
1509 | /* * Initiali ze new tra ckable var iable by s etting its address f ield | |
1510 | * to the n ext availa ble sequen ce number and enteri ng it unde r that | |
1511 | * index in to the var s array. | |
1512 | * / | |
1513 | vo id newVar( JCVariable Decl varDe cl) { | |
1514 | VarSymbo l sym = va rDecl.sym; | |
1515 | vardecls = ArrayUt ils.ensure Capacity(v ardecls, n extadr); | |
1516 | if ((sym .flags() & FINAL) == 0) { | |
1517 | sym. flags_fiel d |= EFFEC TIVELY_FIN AL; | |
1518 | } | |
1519 | sym.adr = nextadr; | |
1520 | vardecls [nextadr] = varDecl; | |
1521 | inits.ex cl(nextadr ); | |
1522 | uninits. incl(nexta dr); | |
1523 | nextadr+ +; | |
1524 | } | |
1525 | ||
1526 | /* * Record a n initiali zation of a trackabl e variable . | |
1527 | * / | |
1528 | vo id letInit (Diagnosti cPosition pos, VarSy mbol sym) { | |
1529 | if (sym. adr >= fir stadr && t rackable(s ym)) { | |
1530 | if ( (sym.flags () & EFFEC TIVELY_FIN AL) != 0) { | |
1531 | if (!unini ts.isMembe r(sym.adr) ) { | |
1532 | //assi gnment tar geting an effectivel y final va riable | |
1533 | //make s the vari able lose its status of effect ively fina l | |
1534 | //if t he variabl e is _not_ definitiv ely unassi gned | |
1535 | sym.fl ags_field &= ~EFFECT IVELY_FINA L; | |
1536 | } else { | |
1537 | uninit (sym); | |
1538 | } | |
1539 | } el se if ((sy m.flags() & FINAL) ! = 0) { | |
1540 | if ((sym.f lags() & P ARAMETER) != 0) { | |
1541 | if ((s ym.flags() & UNION) != 0) { // multi-catc h paramete r | |
1542 | lo g.error(po s, "multic atch.param eter.may.n ot.be.assi gned", sym ); | |
1543 | } else { | |
1544 | lo g.error(po s, "final. parameter. may.not.be .assigned" , | |
1545 | sym); | |
1546 | } | |
1547 | } else if (!uninits. isMember(s ym.adr)) { | |
1548 | log.er ror(pos, f lowKind.er rKey, sym) ; | |
1549 | } else { | |
1550 | uninit (sym); | |
1551 | } | |
1552 | } | |
1553 | init s.incl(sym .adr); | |
1554 | } else i f ((sym.fl ags() & FI NAL) != 0) { | |
1555 | log. error(pos, "var.migh t.already. be.assigne d", sym); | |
1556 | } | |
1557 | } | |
1558 | // where | |
1559 | void uni nit(VarSym bol sym) { | |
1560 | if ( !inits.isM ember(sym. adr)) { | |
1561 | // reachab le assignm ent | |
1562 | uninits.ex cl(sym.adr ); | |
1563 | uninitsTry .excl(sym. adr); | |
1564 | } el se { | |
1565 | //log.rawW arning(pos , "unreach able assig nment");// DEBUG | |
1566 | uninits.ex cl(sym.adr ); | |
1567 | } | |
1568 | } | |
1569 | ||
1570 | /* * If tree is either a simple n ame or of the form t his.name o r | |
1571 | * C.this.n ame, and t ree repres ents a tra ckable var iable, | |
1572 | * record a n initiali zation of the variab le. | |
1573 | * / | |
1574 | vo id letInit (JCTree tr ee) { | |
1575 | tree = T reeInfo.sk ipParens(t ree); | |
1576 | if (tree .hasTag(ID ENT) || tr ee.hasTag( SELECT)) { | |
1577 | Symb ol sym = T reeInfo.sy mbol(tree) ; | |
1578 | if ( sym.kind = = VAR) { | |
1579 | letInit(tr ee.pos(), (VarSymbol )sym); | |
1580 | } | |
1581 | } | |
1582 | } | |
1583 | ||
1584 | /* * Check th at trackab le variabl e is initi alized. | |
1585 | * / | |
1586 | vo id checkIn it(Diagnos ticPositio n pos, Var Symbol sym ) { | |
1587 | checkIni t(pos, sym , "var.mig ht.not.hav e.been.ini tialized") ; | |
1588 | } | |
1589 | ||
1590 | vo id checkIn it(Diagnos ticPositio n pos, Var Symbol sym , String e rrkey) { | |
1591 | if ((sym .adr >= fi rstadr || sym.owner. kind != TY P) && | |
1592 | trac kable(sym) && | |
1593 | !ini ts.isMembe r(sym.adr) ) { | |
1594 | log. error(pos, errkey, s ym); | |
1595 | init s.incl(sym .adr); | |
1596 | } | |
1597 | } | |
1598 | ||
1599 | /* * Utility method to reset seve ral Bits i nstances. | |
1600 | * / | |
1601 | pr ivate void resetBits (Bits... b its) { | |
1602 | for (Bit s b : bits ) { | |
1603 | b.re set(); | |
1604 | } | |
1605 | } | |
1606 | ||
1607 | /* * Split (d uplicate) inits/unin its into W henTrue/Wh enFalse se ts | |
1608 | * / | |
1609 | vo id split(b oolean set ToNull) { | |
1610 | initsWhe nFalse.ass ign(inits) ; | |
1611 | uninitsW henFalse.a ssign(unin its); | |
1612 | initsWhe nTrue.assi gn(inits); | |
1613 | uninitsW henTrue.as sign(unini ts); | |
1614 | if (setT oNull) { | |
1615 | rese tBits(init s, uninits ); | |
1616 | } | |
1617 | } | |
1618 | ||
1619 | /* * Merge (i ntersect) inits/unin its from W henTrue/Wh enFalse se ts. | |
1620 | * / | |
1621 | pr otected vo id merge() { | |
1622 | inits.as sign(inits WhenFalse. andSet(ini tsWhenTrue )); | |
1623 | uninits. assign(uni nitsWhenFa lse.andSet (uninitsWh enTrue)); | |
1624 | } | |
1625 | ||
1626 | /* *** ********** ********** ********** ********** ********** ********** ********* | |
1627 | * Vis itor metho ds for sta tements an d definiti ons | |
1628 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
1629 | ||
1630 | /* * Analyze an express ion. Make sure to se t (un)init s rather t han | |
1631 | * (un)init sWhenTrue( WhenFalse) on exit. | |
1632 | * / | |
1633 | vo id scanExp r(JCTree t ree) { | |
1634 | if (tree != null) { | |
1635 | scan (tree); | |
1636 | if ( inits.isRe set()) { | |
1637 | merge(); | |
1638 | } | |
1639 | } | |
1640 | } | |
1641 | ||
1642 | /* * Analyze a list of expression s. | |
1643 | * / | |
1644 | vo id scanExp rs(List<? extends JC Expression > trees) { | |
1645 | if (tree s != null) | |
1646 | for (List<? ex tends JCEx pression> l = trees; l.nonEmpt y(); l = l .tail) | |
1647 | scanExpr(l .head); | |
1648 | } | |
1649 | ||
1650 | /* * Analyze a conditio n. Make su re to set (un)initsW henTrue(Wh enFalse) | |
1651 | * rather t han (un)in its on exi t. | |
1652 | * / | |
1653 | vo id scanCon d(JCTree t ree) { | |
1654 | if (tree .type.isFa lse()) { | |
1655 | if ( inits.isRe set()) mer ge(); | |
1656 | init sWhenTrue. assign(ini ts); | |
1657 | init sWhenTrue. inclRange( firstadr, nextadr); | |
1658 | unin itsWhenTru e.assign(u ninits); | |
1659 | unin itsWhenTru e.inclRang e(firstadr , nextadr) ; | |
1660 | init sWhenFalse .assign(in its); | |
1661 | unin itsWhenFal se.assign( uninits); | |
1662 | } else i f (tree.ty pe.isTrue( )) { | |
1663 | if ( inits.isRe set()) mer ge(); | |
1664 | init sWhenFalse .assign(in its); | |
1665 | init sWhenFalse .inclRange (firstadr, nextadr); | |
1666 | unin itsWhenFal se.assign( uninits); | |
1667 | unin itsWhenFal se.inclRan ge(firstad r, nextadr ); | |
1668 | init sWhenTrue. assign(ini ts); | |
1669 | unin itsWhenTru e.assign(u ninits); | |
1670 | } else { | |
1671 | scan (tree); | |
1672 | if ( !inits.isR eset()) | |
1673 | split(tree .type != s yms.unknow nType); | |
1674 | } | |
1675 | if (tree .type != s yms.unknow nType) { | |
1676 | rese tBits(init s, uninits ); | |
1677 | } | |
1678 | } | |
1679 | ||
1680 | /* --------- --- Visito r methods for variou s sorts of trees --- ---------- */ | |
1681 | ||
1682 | pu blic void visitClass Def(JCClas sDecl tree ) { | |
1683 | if (tree .sym == nu ll) { | |
1684 | retu rn; | |
1685 | } | |
1686 | ||
1687 | Lint lin tPrev = li nt; | |
1688 | lint = l int.augmen t(tree.sym ); | |
1689 | try { | |
1690 | if ( tree.sym = = null) { | |
1691 | return; | |
1692 | } | |
1693 | ||
1694 | JCCl assDecl cl assDefPrev = classDe f; | |
1695 | int firstadrPr ev = first adr; | |
1696 | int nextadrPre v = nextad r; | |
1697 | List Buffer<Ass ignPending Exit> pend ingExitsPr ev = pendi ngExits; | |
1698 | ||
1699 | pend ingExits = new ListB uffer<>(); | |
1700 | if ( tree.name != names.e mpty) { | |
1701 | firstadr = nextadr; | |
1702 | } | |
1703 | clas sDef = tre e; | |
1704 | try { | |
1705 | // define all the st atic field s | |
1706 | for (List< JCTree> l = tree.def s; l.nonEm pty(); l = l.tail) { | |
1707 | if (l.head .hasTag(
|
|
1708 | JC VariableDe cl def = ( JCVariable Decl)l.hea d; | |
1709 | if ((def.mod s.flags & STATIC) != 0) { | |
1710 | VarSymbo l sym = de f.sym; | |
1711 | if (trac kable(sym) ) { | |
1712 | newV ar(def); | |
1713 | } | |
1714 | } | |
1715 | } | |
1716 | } | |
1717 | ||
1718 | // process all the s tatic init ializers | |
1719 | for (List< JCTree> l = tree.def s; l.nonEm pty(); l = l.tail) { | |
1720 | if (!l .head.hasT ag(METHODD EF) && | |
1721 | (T reeInfo.fl ags(l.head ) & STATIC ) != 0) { | |
1722 | sc an(l.head) ; | |
1723 | } | |
1724 | } | |
1725 | ||
1726 | // define all the in stance fie lds | |
1727 | for (List< JCTree> l = tree.def s; l.nonEm pty(); l = l.tail) { | |
1728 | if (l.head .hasTag(
|
|
1729 | JC VariableDe cl def = ( JCVariable Decl)l.hea d; | |
1730 | if ((def.mod s.flags & STATIC) == 0) { | |
1731 | VarSymbo l sym = de f.sym; | |
1732 | if (trac kable(sym) ) { | |
1733 | newV ar(def); | |
1734 | } | |
1735 | } | |
1736 | } | |
1737 | } | |
1738 | // process all the i nstance in itializers | |
1739 | for (List< JCTree> l = tree.def s; l.nonEm pty(); l = l.tail) { | |
1740 | if (!l .head.hasT ag(METHODD EF) && | |
1741 | (T reeInfo.fl ags(l.head ) & STATIC ) == 0) { | |
1742 | sc an(l.head) ; | |
1743 | } | |
1744 | } | |
1745 | ||
1746 | // process all the m ethods | |
1747 | for (List< JCTree> l = tree.def s; l.nonEm pty(); l = l.tail) { | |
1748 | if (l. head.hasTa g(METHODDE F)) { | |
1749 | sc an(l.head) ; | |
1750 | } | |
1751 | } | |
1752 | } fi nally { | |
1753 | pendingExi ts = pendi ngExitsPre v; | |
1754 | nextadr = nextadrPre v; | |
1755 | firstadr = firstadrP rev; | |
1756 | classDef = classDefP rev; | |
1757 | } | |
1758 | } finall y { | |
1759 | lint = lintPre v; | |
1760 | } | |
1761 | } | |
1762 | ||
1763 | pu blic void visitMetho dDef(JCMet hodDecl tr ee) { | |
1764 | if (tree .body == n ull) { | |
1765 | retu rn; | |
1766 | } | |
1767 | ||
1768 | /* Memb erEnter ca n generate synthetic methods i gnore them | |
1769 | */ | |
1770 | if ((tre e.sym.flag s() & SYNT HETIC) != 0) { | |
1771 | retu rn; | |
1772 | } | |
1773 | ||
1774 | Lint lin tPrev = li nt; | |
1775 | lint = l int.augmen t(tree.sym ); | |
1776 | try { | |
1777 | if ( tree.body == null) { | |
1778 | return; | |
1779 | } | |
1780 | /* Ignore syn thetic met hods, exce pt for tra nslated la mbda metho ds. | |
1781 | */ | |
1782 | if ( (tree.sym. flags() & (SYNTHETIC | LAMBDA_ METHOD)) = = SYNTHETI C) { | |
1783 | return; | |
1784 | } | |
1785 | ||
1786 | fina l Bits ini tsPrev = n ew Bits(in its); | |
1787 | fina l Bits uni nitsPrev = new Bits( uninits); | |
1788 | int nextadrPre v = nextad r; | |
1789 | int firstadrPr ev = first adr; | |
1790 | int returnadrP rev = retu rnadr; | |
1791 | ||
1792 | Asse rt.check(p endingExit s.isEmpty( )); | |
1793 | bool ean lastIn itialConst ructor = i sInitialCo nstructor; | |
1794 | try { | |
1795 | isInitialC onstructor = TreeInf o.isInitia lConstruct or(tree); | |
1796 | ||
1797 | if (!isIni tialConstr uctor) { | |
1798 | firsta dr = nexta dr; | |
1799 | } | |
1800 | for (List< JCVariable Decl> l = tree.param s; l.nonEm pty(); l = l.tail) { | |
1801 | JCVari ableDecl d ef = l.hea d; | |
1802 | scan(d ef); | |
1803 | Assert .check((de f.sym.flag s() & PARA METER) != 0, "Method parameter without P ARAMETER f lag"); | |
1804 | /* If we are ex ecuting th e code fro m Gen, the n there ca n be | |
1805 | * sy nthetic or mandated variables, ignore th em. | |
1806 | */ | |
1807 | initPa ram(def); | |
1808 | } | |
1809 | // else we are in an instance initialize r block; | |
1810 | // leave c aught unch anged. | |
1811 | scan(tree. body); | |
1812 | ||
1813 | if (isInit ialConstru ctor) { | |
1814 | boolea n isSynthe sized = (t ree.sym.fl ags() & | |
1815 | G ENERATEDCO NSTR) != 0 ; | |
1816 | for (i nt i = fir stadr; i < nextadr; i++) { | |
1817 | JC VariableDe cl vardecl = vardecl s[i]; | |
1818 | Va rSymbol va r = vardec l.sym; | |
1819 | if (var.owne r == class Def.sym) { | |
1820 | // choos e the diag nostic pos ition base d on wheth er | |
1821 | // the c tor is def ault(synth esized) or not | |
1822 | if (isSy nthesized) { | |
1823 | chec kInit(Tree Info.diagn osticPosit ionFor(var , vardecl) , | |
1824 | var, "var. not.initia lized.in.d efault.con structor") ; | |
1825 | } else { | |
1826 | chec kInit(Tree Info.diagE ndPos(tree .body), va r); | |
1827 | } | |
1828 | } | |
1829 | } | |
1830 | } | |
1831 | List<Assig nPendingEx it> exits = pendingE xits.toLis t(); | |
1832 | pendingExi ts = new L istBuffer< >(); | |
1833 | while (exi ts.nonEmpt y()) { | |
1834 | Assign PendingExi t exit = e xits.head; | |
1835 | exits = exits.ta il; | |
1836 | Assert .check(exi t.tree.has Tag(RETURN ), exit.tr ee); | |
1837 | if (is InitialCon structor) { | |
1838 | in its.assign (exit.exit _inits); | |
1839 | fo r (int i = firstadr; i < nexta dr; i++) { | |
1840 | checkIni t(exit.tre e.pos(), v ardecls[i] .sym); | |
1841 | } | |
1842 | } | |
1843 | } | |
1844 | } fi nally { | |
1845 | inits.assi gn(initsPr ev); | |
1846 | uninits.as sign(unini tsPrev); | |
1847 | nextadr = nextadrPre v; | |
1848 | firstadr = firstadrP rev; | |
1849 | returnadr = returnad rPrev; | |
1850 | isInitialC onstructor = lastIni tialConstr uctor; | |
1851 | } | |
1852 | } finall y { | |
1853 | lint = lintPre v; | |
1854 | } | |
1855 | } | |
1856 | ||
1857 | pr otected vo id initPar am(JCVaria bleDecl de f) { | |
1858 | inits.in cl(def.sym .adr); | |
1859 | uninits. excl(def.s ym.adr); | |
1860 | } | |
1861 | ||
1862 | pu blic void visitVarDe f(JCVariab leDecl tre e) { | |
1863 | Lint lin tPrev = li nt; | |
1864 | lint = l int.augmen t(tree.sym ); | |
1865 | try{ | |
1866 | bool ean track = trackabl e(tree.sym ); | |
1867 | if ( track && t ree.sym.ow ner.kind = = MTH) { | |
1868 | newVar(tre e); | |
1869 | } | |
1870 | if ( tree.init != null) { | |
1871 | scanExpr(t ree.init); | |
1872 | if (track) { | |
1873 | letIni t(tree.pos (), tree.s ym); | |
1874 | } | |
1875 | } | |
1876 | } finall y { | |
1877 | lint = lintPre v; | |
1878 | } | |
1879 | } | |
1880 | ||
1881 | pu blic void visitBlock (JCBlock t ree) { | |
1882 | int next adrPrev = nextadr; | |
1883 | scan(tre e.stats); | |
1884 | nextadr = nextadrP rev; | |
1885 | } | |
1886 | ||
1887 | pu blic void visitDoLoo p(JCDoWhil eLoop tree ) { | |
1888 | ListBuff er<AssignP endingExit > prevPend ingExits = pendingEx its; | |
1889 | FlowKind prevFlowK ind = flow Kind; | |
1890 | flowKind = FlowKin d.NORMAL; | |
1891 | final Bi ts initsSk ip = new B its(true); | |
1892 | final Bi ts uninits Skip = new Bits(true ); | |
1893 | pendingE xits = new ListBuffe r<>(); | |
1894 | int prev Errors = l og.nerrors ; | |
1895 | do { | |
1896 | fina l Bits uni nitsEntry = new Bits (uninits); | |
1897 | unin itsEntry.e xcludeFrom (nextadr); | |
1898 | scan (tree.body ); | |
1899 | reso lveContinu es(tree); | |
1900 | scan Cond(tree. cond); | |
1901 | if ( !flowKind. isFinal()) { | |
1902 | initsSkip. assign(ini tsWhenFals e); | |
1903 | uninitsSki p.assign(u ninitsWhen False); | |
1904 | } | |
1905 | if ( log.nerror s != prev Errors || | |
1906 | flowKind.i sFinal() | | | |
1907 | new Bits(u ninitsEntr y).diffSet (uninitsWh enTrue).ne xtBit(firs tadr)==-1) | |
1908 | break; | |
1909 | init s.assign(i nitsWhenTr ue); | |
1910 | unin its.assign (uninitsEn try.andSet (uninitsWh enTrue)); | |
1911 | flow Kind = Flo wKind.SPEC ULATIVE_LO OP; | |
1912 | } while (true); | |
1913 | flowKind = prevFlo wKind; | |
1914 | inits.as sign(inits Skip); | |
1915 | uninits. assign(uni nitsSkip); | |
1916 | resolveB reaks(tree , prevPend ingExits); | |
1917 | } | |
1918 | ||
1919 | pu blic void visitWhile Loop(JCWhi leLoop tre e) { | |
1920 | ListBuff er<AssignP endingExit > prevPend ingExits = pendingEx its; | |
1921 | FlowKind prevFlowK ind = flow Kind; | |
1922 | flowKind = FlowKin d.NORMAL; | |
1923 | final Bi ts initsSk ip = new B its(true); | |
1924 | final Bi ts uninits Skip = new Bits(true ); | |
1925 | pendingE xits = new ListBuffe r<>(); | |
1926 | int prev Errors = l og.nerrors ; | |
1927 | final Bi ts uninits Entry = ne w Bits(uni nits); | |
1928 | uninitsE ntry.exclu deFrom(nex tadr); | |
1929 | do { | |
1930 | scan Cond(tree. cond); | |
1931 | if ( !flowKind. isFinal()) { | |
1932 | initsSkip. assign(ini tsWhenFals e) ; | |
1933 | uninitsSki p.assign(u ninitsWhen False); | |
1934 | } | |
1935 | init s.assign(i nitsWhenTr ue); | |
1936 | unin its.assign (uninitsWh enTrue); | |
1937 | scan (tree.body ); | |
1938 | reso lveContinu es(tree); | |
1939 | if ( log.nerror s != prevE rrors || | |
1940 | flowKind.i sFinal() | | | |
1941 | new Bits(u ninitsEntr y).diffSet (uninits). nextBit(fi rstadr) == -1) { | |
1942 | break; | |
1943 | } | |
1944 | unin its.assign (uninitsEn try.andSet (uninits)) ; | |
1945 | flow Kind = Flo wKind.SPEC ULATIVE_LO OP; | |
1946 | } while (true); | |
1947 | flowKind = prevFlo wKind; | |
1948 | //a vari able is DA /DU after the while statement, if it's D A/DU assum ing the | |
1949 | //branch is not ta ken AND if it's DA/D U before a ny break s tatement | |
1950 | inits.as sign(inits Skip); | |
1951 | uninits. assign(uni nitsSkip); | |
1952 | resolveB reaks(tree , prevPend ingExits); | |
1953 | } | |
1954 | ||
1955 | pu blic void visitForLo op(JCForLo op tree) { | |
1956 | ListBuff er<AssignP endingExit > prevPend ingExits = pendingEx its; | |
1957 | FlowKind prevFlowK ind = flow Kind; | |
1958 | flowKind = FlowKin d.NORMAL; | |
1959 | int next adrPrev = nextadr; | |
1960 | scan(tre e.init); | |
1961 | final Bi ts initsSk ip = new B its(true); | |
1962 | final Bi ts uninits Skip = new Bits(true ); | |
1963 | pendingE xits = new ListBuffe r<>(); | |
1964 | int prev Errors = l og.nerrors ; | |
1965 | do { | |
1966 | fina l Bits uni nitsEntry = new Bits (uninits); | |
1967 | unin itsEntry.e xcludeFrom (nextadr); | |
1968 | if ( tree.cond != null) { | |
1969 | scanCond(t ree.cond); | |
1970 | if (!flowK ind.isFina l()) { | |
1971 | initsS kip.assign (initsWhen False); | |
1972 | uninit sSkip.assi gn(uninits WhenFalse) ; | |
1973 | } | |
1974 | inits.assi gn(initsWh enTrue); | |
1975 | uninits.as sign(unini tsWhenTrue ); | |
1976 | } el se if (!fl owKind.isF inal()) { | |
1977 | initsSkip. assign(ini ts); | |
1978 | initsSkip. inclRange( firstadr, nextadr); | |
1979 | uninitsSki p.assign(u ninits); | |
1980 | uninitsSki p.inclRang e(firstadr , nextadr) ; | |
1981 | } | |
1982 | scan (tree.body ); | |
1983 | reso lveContinu es(tree); | |
1984 | scan (tree.step ); | |
1985 | if ( log.nerror s != prevE rrors || | |
1986 | flowKind.i sFinal() | | | |
1987 | new Bits(u ninitsEntr y).diffSet (uninits). nextBit(fi rstadr) == -1) | |
1988 | break; | |
1989 | unin its.assign (uninitsEn try.andSet (uninits)) ; | |
1990 | flow Kind = Flo wKind.SPEC ULATIVE_LO OP; | |
1991 | } while (true); | |
1992 | flowKind = prevFlo wKind; | |
1993 | //a vari able is DA /DU after a for loop , if it's DA/DU assu ming the | |
1994 | //branch is not ta ken AND if it's DA/D U before a ny break s tatement | |
1995 | inits.as sign(inits Skip); | |
1996 | uninits. assign(uni nitsSkip); | |
1997 | resolveB reaks(tree , prevPend ingExits); | |
1998 | nextadr = nextadrP rev; | |
1999 | } | |
2000 | ||
2001 | pu blic void visitForea chLoop(JCE nhancedFor Loop tree) { | |
2002 | visitVar Def(tree.v ar); | |
2003 | ||
2004 | ListBuff er<AssignP endingExit > prevPend ingExits = pendingEx its; | |
2005 | FlowKind prevFlowK ind = flow Kind; | |
2006 | flowKind = FlowKin d.NORMAL; | |
2007 | int next adrPrev = nextadr; | |
2008 | scan(tre e.expr); | |
2009 | final Bi ts initsSt art = new Bits(inits ); | |
2010 | final Bi ts uninits Start = ne w Bits(uni nits); | |
2011 | ||
2012 | letInit( tree.pos() , tree.var .sym); | |
2013 | pendingE xits = new ListBuffe r<>(); | |
2014 | int prev Errors = l og.nerrors ; | |
2015 | do { | |
2016 | fina l Bits uni nitsEntry = new Bits (uninits); | |
2017 | unin itsEntry.e xcludeFrom (nextadr); | |
2018 | scan (tree.body ); | |
2019 | reso lveContinu es(tree); | |
2020 | if ( log.nerror s != prevE rrors || | |
2021 | flowKind.i sFinal() | | | |
2022 | new Bits(u ninitsEntr y).diffSet (uninits). nextBit(fi rstadr) == -1) | |
2023 | break; | |
2024 | unin its.assign (uninitsEn try.andSet (uninits)) ; | |
2025 | flow Kind = Flo wKind.SPEC ULATIVE_LO OP; | |
2026 | } while (true); | |
2027 | flowKind = prevFlo wKind; | |
2028 | inits.as sign(inits Start); | |
2029 | uninits. assign(uni nitsStart. andSet(uni nits)); | |
2030 | resolveB reaks(tree , prevPend ingExits); | |
2031 | nextadr = nextadrP rev; | |
2032 | } | |
2033 | ||
2034 | pu blic void visitLabel led(JCLabe ledStateme nt tree) { | |
2035 | ListBuff er<AssignP endingExit > prevPend ingExits = pendingEx its; | |
2036 | pendingE xits = new ListBuffe r<>(); | |
2037 | scan(tre e.body); | |
2038 | resolveB reaks(tree , prevPend ingExits); | |
2039 | } | |
2040 | ||
2041 | pu blic void visitSwitc h(JCSwitch tree) { | |
2042 | ListBuff er<AssignP endingExit > prevPend ingExits = pendingEx its; | |
2043 | pendingE xits = new ListBuffe r<>(); | |
2044 | int next adrPrev = nextadr; | |
2045 | scanExpr (tree.sele ctor); | |
2046 | final Bi ts initsSw itch = new Bits(init s); | |
2047 | final Bi ts uninits Switch = n ew Bits(un inits); | |
2048 | boolean hasDefault = false; | |
2049 | for (Lis t<JCCase> l = tree.c ases; l.no nEmpty(); l = l.tail ) { | |
2050 | init s.assign(i nitsSwitch ); | |
2051 | unin its.assign (uninits.a ndSet(unin itsSwitch) ); | |
2052 | JCCa se c = l.h ead; | |
2053 | if ( c.pat == n ull) { | |
2054 | hasDefault = true; | |
2055 | } el se { | |
2056 | scanExpr(c .pat); | |
2057 | } | |
2058 | if ( hasDefault ) { | |
2059 | inits.assi gn(initsSw itch); | |
2060 | uninits.as sign(unini ts.andSet( uninitsSwi tch)); | |
2061 | } | |
2062 | scan (c.stats); | |
2063 | addV ars(c.stat s, initsSw itch, unin itsSwitch) ; | |
2064 | if ( !hasDefaul t) { | |
2065 | inits.assi gn(initsSw itch); | |
2066 | uninits.as sign(unini ts.andSet( uninitsSwi tch)); | |
2067 | } | |
2068 | // W arn about fall-throu gh if lint switch fa llthrough enabled. | |
2069 | } | |
2070 | if (!has Default) { | |
2071 | init s.andSet(i nitsSwitch ); | |
2072 | } | |
2073 | resolveB reaks(tree , prevPend ingExits); | |
2074 | nextadr = nextadrP rev; | |
2075 | } | |
2076 | // where | |
2077 | /** Add any variab les define d in stats to inits and uninit s. */ | |
2078 | private void addVa rs(List<JC Statement> stats, fi nal Bits i nits, | |
2079 | final Bits uninits) { | |
2080 | for (;stats.no nEmpty(); stats = st ats.tail) { | |
2081 | JCTree sta t = stats. head; | |
2082 | if (stat.h asTag(
|
|
2083 | int ad r = ((JCVa riableDecl ) stat).sy m.adr; | |
2084 | inits. excl(adr); | |
2085 | uninit s.incl(adr ); | |
2086 | } | |
2087 | } | |
2088 | } | |
2089 | ||
2090 | pu blic void visitTry(J CTry tree) { | |
2091 | ListBuff er<JCVaria bleDecl> r esourceVar Decls = ne w ListBuff er<>(); | |
2092 | final Bi ts uninits TryPrev = new Bits(u ninitsTry) ; | |
2093 | ListBuff er<AssignP endingExit > prevPend ingExits = pendingEx its; | |
2094 | pendingE xits = new ListBuffe r<>(); | |
2095 | final Bi ts initsTr y = new Bi ts(inits); | |
2096 | uninitsT ry.assign( uninits); | |
2097 | for (JCT ree resour ce : tree. resources) { | |
2098 | if ( resource i nstanceof JCVariable Decl) { | |
2099 | JCVariable Decl vdecl = (JCVari ableDecl) resource; | |
2100 | visitVarDe f(vdecl); | |
2101 | unrefdReso urces.ente r(vdecl.sy m); | |
2102 | resourceVa rDecls.app end(vdecl) ; | |
2103 | } el se if (res ource inst anceof JCE xpression) { | |
2104 | scanExpr(( JCExpressi on) resour ce); | |
2105 | } el se { | |
2106 | throw new AssertionE rror(tree) ; // pars er error | |
2107 | } | |
2108 | } | |
2109 | scan(tre e.body); | |
2110 | uninitsT ry.andSet( uninits); | |
2111 | final Bi ts initsEn d = new Bi ts(inits); | |
2112 | final Bi ts uninits End = new Bits(unini ts); | |
2113 | int next adrCatch = nextadr; | |
2114 | ||
2115 | if (!res ourceVarDe cls.isEmpt y() && | |
2116 | lint.isEna bled(Lint. LintCatego ry.TRY)) { | |
2117 | for (JCVariabl eDecl resV ar : resou rceVarDecl s) { | |
2118 | if (unrefd Resources. includes(r esVar.sym) ) { | |
2119 | log.wa rning(Lint .LintCateg ory.TRY, r esVar.pos( ), | |
2120 | "try .resource. not.refere nced", res Var.sym); | |
2121 | unrefd Resources. remove(res Var.sym); | |
2122 | } | |
2123 | } | |
2124 | } | |
2125 | ||
2126 | /* The analysis o f each cat ch should be indepen dent. | |
2127 | * Each one shoul d have the same init ial values of inits and | |
2128 | * unin its. | |
2129 | */ | |
2130 | final Bi ts initsCa tchPrev = new Bits(i nitsTry); | |
2131 | final Bi ts uninits CatchPrev = new Bits (uninitsTr y); | |
2132 | ||
2133 | for (Lis t<JCCatch> l = tree. catchers; l.nonEmpty (); l = l. tail) { | |
2134 | JCVa riableDecl param = l .head.para m; | |
2135 | init s.assign(i nitsCatchP rev); | |
2136 | unin its.assign (uninitsCa tchPrev); | |
2137 | scan (param); | |
2138 | /* I f this is a TWR and we are exe cuting the code from Gen, | |
2139 | * t hen there can be syn thetic var iables, ig nore them. | |
2140 | */ | |
2141 | init Param(para m); | |
2142 | scan (l.head.bo dy); | |
2143 | init sEnd.andSe t(inits); | |
2144 | unin itsEnd.and Set(uninit s); | |
2145 | next adr = next adrCatch; | |
2146 | } | |
2147 | if (tree .finalizer != null) { | |
2148 | init s.assign(i nitsTry); | |
2149 | unin its.assign (uninitsTr y); | |
2150 | List Buffer<Ass ignPending Exit> exit s = pendin gExits; | |
2151 | pend ingExits = prevPendi ngExits; | |
2152 | scan (tree.fina lizer); | |
2153 | if ( !tree.fina llyCanComp leteNormal ly) { | |
2154 | // discard exits and exception s from try and final ly | |
2155 | } el se { | |
2156 | uninits.an dSet(unini tsEnd); | |
2157 | // FIX: th is doesn't preserve source ord er of exit s in catch | |
2158 | // versus finally! | |
2159 | while (exi ts.nonEmpt y()) { | |
2160 | Assign PendingExi t exit = e xits.next( ); | |
2161 | if (ex it.exit_in its != nul l) { | |
2162 | ex it.exit_in its.orSet( inits); | |
2163 | ex it.exit_un inits.andS et(uninits ); | |
2164 | } | |
2165 | pendin gExits.app end(exit); | |
2166 | } | |
2167 | inits.orSe t(initsEnd ); | |
2168 | } | |
2169 | } else { | |
2170 | init s.assign(i nitsEnd); | |
2171 | unin its.assign (uninitsEn d); | |
2172 | List Buffer<Ass ignPending Exit> exit s = pendin gExits; | |
2173 | pend ingExits = prevPendi ngExits; | |
2174 | whil e (exits.n onEmpty()) pendingEx its.append (exits.nex t()); | |
2175 | } | |
2176 | uninitsT ry.andSet( uninitsTry Prev).andS et(uninits ); | |
2177 | } | |
2178 | ||
2179 | pu blic void visitCondi tional(JCC onditional tree) { | |
2180 | scanCond (tree.cond ); | |
2181 | final Bi ts initsBe foreElse = new Bits( initsWhenF alse); | |
2182 | final Bi ts uninits BeforeElse = new Bit s(uninitsW henFalse); | |
2183 | inits.as sign(inits WhenTrue); | |
2184 | uninits. assign(uni nitsWhenTr ue); | |
2185 | if (tree .truepart. type.hasTa g(BOOLEAN) && | |
2186 | tree .falsepart .type.hasT ag(BOOLEAN )) { | |
2187 | // i f b and c are boolea n valued, then | |
2188 | // v is (un)as signed aft er a?b:c w hen true i ff | |
2189 | // v is (un )assigned after b wh en true an d | |
2190 | // v is (un )assigned after c wh en true | |
2191 | scan Cond(tree. truepart); | |
2192 | fina l Bits ini tsAfterThe nWhenTrue = new Bits (initsWhen True); | |
2193 | fina l Bits ini tsAfterThe nWhenFalse = new Bit s(initsWhe nFalse); | |
2194 | fina l Bits uni nitsAfterT henWhenTru e = new Bi ts(uninits WhenTrue); | |
2195 | fina l Bits uni nitsAfterT henWhenFal se = new B its(uninit sWhenFalse ); | |
2196 | init s.assign(i nitsBefore Else); | |
2197 | unin its.assign (uninitsBe foreElse); | |
2198 | scan Cond(tree. falsepart) ; | |
2199 | init sWhenTrue. andSet(ini tsAfterThe nWhenTrue) ; | |
2200 | init sWhenFalse .andSet(in itsAfterTh enWhenFals e); | |
2201 | unin itsWhenTru e.andSet(u ninitsAfte rThenWhenT rue); | |
2202 | unin itsWhenFal se.andSet( uninitsAft erThenWhen False); | |
2203 | } else { | |
2204 | scan Expr(tree. truepart); | |
2205 | fina l Bits ini tsAfterThe n = new Bi ts(inits); | |
2206 | fina l Bits uni nitsAfterT hen = new Bits(unini ts); | |
2207 | init s.assign(i nitsBefore Else); | |
2208 | unin its.assign (uninitsBe foreElse); | |
2209 | scan Expr(tree. falsepart) ; | |
2210 | init s.andSet(i nitsAfterT hen); | |
2211 | unin its.andSet (uninitsAf terThen); | |
2212 | } | |
2213 | } | |
2214 | ||
2215 | pu blic void visitIf(JC If tree) { | |
2216 | scanCond (tree.cond ); | |
2217 | final Bi ts initsBe foreElse = new Bits( initsWhenF alse); | |
2218 | final Bi ts uninits BeforeElse = new Bit s(uninitsW henFalse); | |
2219 | inits.as sign(inits WhenTrue); | |
2220 | uninits. assign(uni nitsWhenTr ue); | |
2221 | scan(tre e.thenpart ); | |
2222 | if (tree .elsepart != null) { | |
2223 | fina l Bits ini tsAfterThe n = new Bi ts(inits); | |
2224 | fina l Bits uni nitsAfterT hen = new Bits(unini ts); | |
2225 | init s.assign(i nitsBefore Else); | |
2226 | unin its.assign (uninitsBe foreElse); | |
2227 | scan (tree.else part); | |
2228 | init s.andSet(i nitsAfterT hen); | |
2229 | unin its.andSet (uninitsAf terThen); | |
2230 | } else { | |
2231 | init s.andSet(i nitsBefore Else); | |
2232 | unin its.andSet (uninitsBe foreElse); | |
2233 | } | |
2234 | } | |
2235 | ||
2236 | @O verride | |
2237 | pu blic void visitBreak (JCBreak t ree) { | |
2238 | recordEx it(new Ass ignPending Exit(tree, inits, un inits)); | |
2239 | } | |
2240 | ||
2241 | @O verride | |
2242 | pu blic void visitConti nue(JCCont inue tree) { | |
2243 | recordEx it(new Ass ignPending Exit(tree, inits, un inits)); | |
2244 | } | |
2245 | ||
2246 | @O verride | |
2247 | pu blic void visitRetur n(JCReturn tree) { | |
2248 | scanExpr (tree.expr ); | |
2249 | recordEx it(new Ass ignPending Exit(tree, inits, un inits)); | |
2250 | } | |
2251 | ||
2252 | pu blic void visitThrow (JCThrow t ree) { | |
2253 | scanExpr (tree.expr ); | |
2254 | markDead (); | |
2255 | } | |
2256 | ||
2257 | pu blic void visitApply (JCMethodI nvocation tree) { | |
2258 | scanExpr (tree.meth ); | |
2259 | scanExpr s(tree.arg s); | |
2260 | } | |
2261 | ||
2262 | pu blic void visitNewCl ass(JCNewC lass tree) { | |
2263 | scanExpr (tree.encl ); | |
2264 | scanExpr s(tree.arg s); | |
2265 | scan(tre e.def); | |
2266 | } | |
2267 | ||
2268 | @O verride | |
2269 | pu blic void visitLambd a(JCLambda tree) { | |
2270 | final Bi ts prevUni nits = new Bits(unin its); | |
2271 | final Bi ts prevIni ts = new B its(inits) ; | |
2272 | int retu rnadrPrev = returnad r; | |
2273 | ListBuff er<AssignP endingExit > prevPend ing = pend ingExits; | |
2274 | try { | |
2275 | retu rnadr = ne xtadr; | |
2276 | pend ingExits = new ListB uffer<>(); | |
2277 | for (List<JCVa riableDecl > l = tree .params; l .nonEmpty( ); l = l.t ail) { | |
2278 | JCVariable Decl def = l.head; | |
2279 | scan(def); | |
2280 | inits.incl (def.sym.a dr); | |
2281 | uninits.ex cl(def.sym .adr); | |
2282 | } | |
2283 | if ( tree.getBo dyKind() = = JCLambda .BodyKind. EXPRESSION ) { | |
2284 | scanExpr(t ree.body); | |
2285 | } el se { | |
2286 | scan(tree. body); | |
2287 | } | |
2288 | } | |
2289 | finally { | |
2290 | retu rnadr = re turnadrPre v; | |
2291 | unin its.assign (prevUnini ts); | |
2292 | init s.assign(p revInits); | |
2293 | pend ingExits = prevPendi ng; | |
2294 | } | |
2295 | } | |
2296 | ||
2297 | pu blic void visitNewAr ray(JCNewA rray tree) { | |
2298 | scanExpr s(tree.dim s); | |
2299 | scanExpr s(tree.ele ms); | |
2300 | } | |
2301 | ||
2302 | pu blic void visitAsser t(JCAssert tree) { | |
2303 | final Bi ts initsEx it = new B its(inits) ; | |
2304 | final Bi ts uninits Exit = new Bits(unin its); | |
2305 | scanCond (tree.cond ); | |
2306 | uninitsE xit.andSet (uninitsWh enTrue); | |
2307 | if (tree .detail != null) { | |
2308 | init s.assign(i nitsWhenFa lse); | |
2309 | unin its.assign (uninitsWh enFalse); | |
2310 | scan Expr(tree. detail); | |
2311 | } | |
2312 | inits.as sign(inits Exit); | |
2313 | uninits. assign(uni nitsExit); | |
2314 | } | |
2315 | ||
2316 | pu blic void visitAssig n(JCAssign tree) { | |
2317 | JCTree l hs = TreeI nfo.skipPa rens(tree. lhs); | |
2318 | if (!isI dentOrThis DotIdent(l hs)) | |
2319 | scan Expr(lhs); | |
2320 | scanExpr (tree.rhs) ; | |
2321 | letInit( lhs); | |
2322 | } | |
2323 | pr ivate bool ean isIden tOrThisDot Ident(JCTr ee lhs) { | |
2324 | if (lhs. hasTag(IDE NT)) | |
2325 | retu rn true; | |
2326 | if (!lhs .hasTag(SE LECT)) | |
2327 | retu rn false; | |
2328 | ||
2329 | JCFieldA ccess fa = (JCFieldA ccess)lhs; | |
2330 | return f a.selected .hasTag(ID ENT) && | |
2331 | ( (JCIdent)f a.selected ).name == names._thi s; | |
2332 | } | |
2333 | ||
2334 | // check fie lds access ed through this.<fie ld> are de finitely | |
2335 | // assigned before rea ding their value | |
2336 | pu blic void visitSelec t(JCFieldA ccess tree ) { | |
2337 | super.vi sitSelect( tree); | |
2338 | if (enfo rceThisDot Init && | |
2339 | tree .selected. hasTag(IDE NT) && | |
2340 | ((JC Ident)tree .selected) .name == n ames._this && | |
2341 | tree .sym.kind == VAR) | |
2342 | { | |
2343 | chec kInit(tree .pos(), (V arSymbol)t ree.sym); | |
2344 | } | |
2345 | } | |
2346 | ||
2347 | pu blic void visitAssig nop(JCAssi gnOp tree) { | |
2348 | scanExpr (tree.lhs) ; | |
2349 | scanExpr (tree.rhs) ; | |
2350 | letInit( tree.lhs); | |
2351 | } | |
2352 | ||
2353 | pu blic void visitUnary (JCUnary t ree) { | |
2354 | switch ( tree.getTa g()) { | |
2355 | case NOT : | |
2356 | scan Cond(tree. arg); | |
2357 | fina l Bits t = new Bits( initsWhenF alse); | |
2358 | init sWhenFalse .assign(in itsWhenTru e); | |
2359 | init sWhenTrue. assign(t); | |
2360 | t.as sign(unini tsWhenFals e); | |
2361 | unin itsWhenFal se.assign( uninitsWhe nTrue); | |
2362 | unin itsWhenTru e.assign(t ); | |
2363 | brea k; | |
2364 | case PRE INC: case POSTINC: | |
2365 | case PRE DEC: case POSTDEC: | |
2366 | scan Expr(tree. arg); | |
2367 | letI nit(tree.a rg); | |
2368 | brea k; | |
2369 | default: | |
2370 | scan Expr(tree. arg); | |
2371 | } | |
2372 | } | |
2373 | ||
2374 | pu blic void visitBinar y(JCBinary tree) { | |
2375 | switch ( tree.getTa g()) { | |
2376 | case AND : | |
2377 | scan Cond(tree. lhs); | |
2378 | fina l Bits ini tsWhenFals eLeft = ne w Bits(ini tsWhenFals e); | |
2379 | fina l Bits uni nitsWhenFa lseLeft = new Bits(u ninitsWhen False); | |
2380 | init s.assign(i nitsWhenTr ue); | |
2381 | unin its.assign (uninitsWh enTrue); | |
2382 | scan Cond(tree. rhs); | |
2383 | init sWhenFalse .andSet(in itsWhenFal seLeft); | |
2384 | unin itsWhenFal se.andSet( uninitsWhe nFalseLeft ); | |
2385 | brea k; | |
2386 | case OR: | |
2387 | scan Cond(tree. lhs); | |
2388 | fina l Bits ini tsWhenTrue Left = new Bits(init sWhenTrue) ; | |
2389 | fina l Bits uni nitsWhenTr ueLeft = n ew Bits(un initsWhenT rue); | |
2390 | init s.assign(i nitsWhenFa lse); | |
2391 | unin its.assign (uninitsWh enFalse); | |
2392 | scan Cond(tree. rhs); | |
2393 | init sWhenTrue. andSet(ini tsWhenTrue Left); | |
2394 | unin itsWhenTru e.andSet(u ninitsWhen TrueLeft); | |
2395 | brea k; | |
2396 | default: | |
2397 | scan Expr(tree. lhs); | |
2398 | scan Expr(tree. rhs); | |
2399 | } | |
2400 | } | |
2401 | ||
2402 | pu blic void visitIdent (JCIdent t ree) { | |
2403 | if (tree .sym.kind == VAR) { | |
2404 | chec kInit(tree .pos(), (V arSymbol)t ree.sym); | |
2405 | refe renced(tre e.sym); | |
2406 | } | |
2407 | } | |
2408 | ||
2409 | vo id referen ced(Symbol sym) { | |
2410 | unrefdRe sources.re move(sym); | |
2411 | } | |
2412 | ||
2413 | pu blic void visitAnnot atedType(J CAnnotated Type tree) { | |
2414 | // annot ations don 't get sca nned | |
2415 | tree.und erlyingTyp e.accept(t his); | |
2416 | } | |
2417 | ||
2418 | pu blic void visitTopLe vel(JCComp ilationUni t tree) { | |
2419 | // Do no thing for TopLevel s ince each class is v isited ind ividually | |
2420 | } | |
2421 | ||
2422 | /***** ********** ********** ********** ********** ********** ********** ********* | |
2423 | * mai n method | |
2424 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
2425 | ||
2426 | /* * Perform definite a ssignment/ unassignme nt analysi s on a tre e. | |
2427 | * / | |
2428 | pu blic void analyzeTre e(Env<?> e nv) { | |
2429 | analyzeT ree(env, e nv.tree); | |
2430 | } | |
2431 | ||
2432 | pu blic void analyzeTre e(Env<?> e nv, JCTree tree) { | |
2433 | try { | |
2434 | star tPos = tre e.pos().ge tStartPosi tion(); | |
2435 | ||
2436 | if ( vardecls = = null) | |
2437 | vardecls = new JCVar iableDecl[ 32]; | |
2438 | else | |
2439 | for (int i =0; i<vard ecls.lengt h; i++) | |
2440 | vardec ls[i] = nu ll; | |
2441 | firs tadr = 0; | |
2442 | next adr = 0; | |
2443 | pend ingExits = new ListB uffer<>(); | |
2444 | this .classDef = null; | |
2445 | unre fdResource s = new Sc ope(env.en clClass.sy m); | |
2446 | scan (tree); | |
2447 | } finall y { | |
2448 | // n ote that r ecursive i nvocations of this m ethod fail hard | |
2449 | star tPos = -1; | |
2450 | rese tBits(init s, uninits , uninitsT ry, initsW henTrue, | |
2451 | initsW henFalse, uninitsWhe nTrue, uni nitsWhenFa lse); | |
2452 | if ( vardecls ! = null) { | |
2453 | for (int i =0; i<vard ecls.lengt h; i++) | |
2454 | vardec ls[i] = nu ll; | |
2455 | } | |
2456 | firs tadr = 0; | |
2457 | next adr = 0; | |
2458 | pend ingExits = null; | |
2459 | this .classDef = null; | |
2460 | unre fdResource s = null; | |
2461 | } | |
2462 | } | |
2463 | } | |
2464 | ||
2465 | /** | |
2466 | * Thi s pass imp lements th e last ste p of the d ataflow an alysis, na mely | |
2467 | * the effective ly-final a nalysis ch eck. This checks tha t every lo cal variab le | |
2468 | * ref erence fro m a lambda body/loca l inner cl ass is eit her final or effecti vely final . | |
2469 | * As effectivel y final va riables ar e marked a s such dur ing DA/DU, this pass must run after | |
2470 | * Ass ignAnalyze r. | |
2471 | */ | |
2472 | class CaptureAna lyzer exte nds BaseAn alyzer<Bas eAnalyzer. PendingExi t> { | |
2473 | ||
2474 | JC Tree curre ntTree; // local clas s or lambd a | |
2475 | ||
2476 | @O verride | |
2477 | vo id markDea d() { | |
2478 | //do not hing | |
2479 | } | |
2480 | ||
2481 | @S uppressWar nings("fal lthrough") | |
2482 | vo id checkEf fectivelyF inal(Diagn osticPosit ion pos, V arSymbol s ym) { | |
2483 | if (curr entTree != null && | |
2484 | sym.owner. kind == MT H && | |
2485 | sym.pos < currentTre e.getStart Position() ) { | |
2486 | swit ch (curren tTree.getT ag()) { | |
2487 | case CLASS DEF: | |
2488 | if (!a llowEffect ivelyFinal InInnerCla sses) { | |
2489 | if ((sym.fla gs() & FIN AL) == 0) { | |
2490 | reportIn nerClsNeed sFinalErro r(pos, sym ); | |
2491 | } | |
2492 | br eak; | |
2493 | } | |
2494 | case LAMBD A: | |
2495 | if ((s ym.flags() & (EFFECT IVELY_FINA L | FINAL) ) == 0) { | |
2496 | rep ortEffecti velyFinalE rror(pos, sym); | |
2497 | } | |
2498 | } | |
2499 | } | |
2500 | } | |
2501 | ||
2502 | @S uppressWar nings("fal lthrough") | |
2503 | vo id letInit (JCTree tr ee) { | |
2504 | tree = T reeInfo.sk ipParens(t ree); | |
2505 | if (tree .hasTag(ID ENT) || tr ee.hasTag( SELECT)) { | |
2506 | Symb ol sym = T reeInfo.sy mbol(tree) ; | |
2507 | if ( currentTre e != null && | |
2508 | sym.ki nd == VAR && | |
2509 | sym.ow ner.kind = = MTH && | |
2510 | ((VarS ymbol)sym) .pos < cur rentTree.g etStartPos ition()) { | |
2511 | switch (cu rrentTree. getTag()) { | |
2512 | case C LASSDEF: | |
2513 | if (!allowEf fectivelyF inalInInne rClasses) { | |
2514 | reportIn nerClsNeed sFinalErro r(tree, sy m); | |
2515 | break; | |
2516 | } | |
2517 | case L AMBDA: | |
2518 | re portEffect ivelyFinal Error(tree , sym); | |
2519 | } | |
2520 | } | |
2521 | } | |
2522 | } | |
2523 | ||
2524 | vo id reportE ffectively FinalError (Diagnosti cPosition pos, Symbo l sym) { | |
2525 | String s ubKey = cu rrentTree. hasTag(LAM BDA) ? | |
2526 | "l ambda" : "inner.cls "; | |
2527 | log.erro r(pos, "ca nt.ref.non .effective ly.final.v ar", sym, diags.frag ment(subKe y)); | |
2528 | } | |
2529 | ||
2530 | vo id reportI nnerClsNee dsFinalErr or(Diagnos ticPositio n pos, Sym bol sym) { | |
2531 | log.erro r(pos, | |
2532 | "local.var .accessed. from.icls. needs.fina l", | |
2533 | sym); | |
2534 | } | |
2535 | ||
2536 | /***** ********** ********** ********** ********** ********** ********** ******** | |
2537 | * Vis itor metho ds for sta tements an d definiti ons | |
2538 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
2539 | ||
2540 | /* --------- --- Visito r methods for variou s sorts of trees --- ---------- */ | |
2541 | ||
2542 | pu blic void visitClass Def(JCClas sDecl tree ) { | |
2543 | JCTree p revTree = currentTre e; | |
2544 | try { | |
2545 | curr entTree = tree.sym.i sLocal() ? tree : nu ll; | |
2546 | supe r.visitCla ssDef(tree ); | |
2547 | } finall y { | |
2548 | curr entTree = prevTree; | |
2549 | } | |
2550 | } | |
2551 | ||
2552 | @O verride | |
2553 | pu blic void visitLambd a(JCLambda tree) { | |
2554 | JCTree p revTree = currentTre e; | |
2555 | try { | |
2556 | curr entTree = tree; | |
2557 | supe r.visitLam bda(tree); | |
2558 | } finall y { | |
2559 | curr entTree = prevTree; | |
2560 | } | |
2561 | } | |
2562 | ||
2563 | @O verride | |
2564 | pu blic void visitIdent (JCIdent t ree) { | |
2565 | if (tree .sym.kind == VAR) { | |
2566 | chec kEffective lyFinal(tr ee, (VarSy mbol)tree. sym); | |
2567 | } | |
2568 | } | |
2569 | ||
2570 | pu blic void visitAssig n(JCAssign tree) { | |
2571 | JCTree l hs = TreeI nfo.skipPa rens(tree. lhs); | |
2572 | if (!(lh s instance of JCIdent )) { | |
2573 | scan (lhs); | |
2574 | } | |
2575 | scan(tre e.rhs); | |
2576 | letInit( lhs); | |
2577 | } | |
2578 | ||
2579 | pu blic void visitAssig nop(JCAssi gnOp tree) { | |
2580 | scan(tre e.lhs); | |
2581 | scan(tre e.rhs); | |
2582 | letInit( tree.lhs); | |
2583 | } | |
2584 | ||
2585 | pu blic void visitUnary (JCUnary t ree) { | |
2586 | switch ( tree.getTa g()) { | |
2587 | case PREINC: c ase POSTIN C: | |
2588 | case PREDEC: c ase POSTDE C: | |
2589 | scan(tree. arg); | |
2590 | letInit(tr ee.arg); | |
2591 | break; | |
2592 | defa ult: | |
2593 | scan(tree. arg); | |
2594 | } | |
2595 | } | |
2596 | ||
2597 | pu blic void visitTopLe vel(JCComp ilationUni t tree) { | |
2598 | // Do no thing for TopLevel s ince each class is v isited ind ividually | |
2599 | } | |
2600 | ||
2601 | /***** ********** ********** ********** ********** ********** ********** ********* | |
2602 | * mai n method | |
2603 | ***** ********** ********** ********** ********** ********** ********** ********/ | |
2604 | ||
2605 | /* * Perform definite a ssignment/ unassignme nt analysi s on a tre e. | |
2606 | * / | |
2607 | pu blic void analyzeTre e(Env<Attr Context> e nv, TreeMa ker make) { | |
2608 | analyzeT ree(env, e nv.tree, m ake); | |
2609 | } | |
2610 | pu blic void analyzeTre e(Env<Attr Context> e nv, JCTree tree, Tre eMaker mak e) { | |
2611 | try { | |
2612 | attr Env = env; | |
2613 | Flow .this.make = make; | |
2614 | pend ingExits = new ListB uffer<>(); | |
2615 | scan (tree); | |
2616 | } finall y { | |
2617 | pend ingExits = null; | |
2618 | Flow .this.make = null; | |
2619 | } | |
2620 | } | |
2621 | } | |
2622 | } |
Araxis Merge (but not the data content of this report) is Copyright © 1993-2016 Araxis Ltd (www.araxis.com). All rights reserved.