KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > code > flow > FlowInfo


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.corext.refactoring.code.flow;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Set JavaDoc;
18
19 import org.eclipse.jdt.core.dom.CatchClause;
20 import org.eclipse.jdt.core.dom.ITypeBinding;
21 import org.eclipse.jdt.core.dom.IVariableBinding;
22 import org.eclipse.jdt.core.dom.SimpleName;
23 import org.eclipse.jdt.core.dom.TryStatement;
24
25 public abstract class FlowInfo {
26     
27     // Return statement handling.
28
protected static final int NOT_POSSIBLE= 0;
29     protected static final int UNDEFINED= 1;
30     protected static final int NO_RETURN= 2;
31     protected static final int PARTIAL_RETURN= 3;
32     protected static final int VOID_RETURN= 4;
33     protected static final int VALUE_RETURN= 5;
34     protected static final int THROW= 6;
35
36     // Local access handling.
37
public static final int UNUSED= 1 << 0;
38     public static final int READ= 1 << 1;
39     public static final int READ_POTENTIAL= 1 << 2;
40     public static final int WRITE= 1 << 3;
41     public static final int WRITE_POTENTIAL= 1 << 4;
42     public static final int UNKNOWN= 1 << 5;
43     
44     // Table to merge access modes for condition statements (e.g branch[x] || branch[y]).
45
private static final int[][] ACCESS_MODE_CONDITIONAL_TABLE= {
46     /* UNUSED READ READ_POTENTIAL WRTIE WRITE_POTENTIAL UNKNOWN */
47     /* UNUSED */ { UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
48     /* READ */ { READ_POTENTIAL, READ, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN },
49     /* READ_POTENTIAL */ { READ_POTENTIAL, READ_POTENTIAL, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN },
50     /* WRITE */ { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE, WRITE_POTENTIAL, UNKNOWN },
51     /* WRITE_POTENTIAL */ { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
52     /* UNKNOWN */ { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN }
53     };
54     
55     // Table to change access mode if there is an open branch statement
56
private static final int[] ACCESS_MODE_OPEN_BRANCH_TABLE= {
57     /* UNUSED READ READ_POTENTIAL WRTIE WRITE_POTENTIAL UNKNOWN */
58         UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN
59     };
60     
61     // Table to merge return modes for condition statements (y: fReturnKind, x: other.fReturnKind)
62
private static final int[][] RETURN_KIND_CONDITIONAL_TABLE = {
63     /* NOT_POSSIBLE UNDEFINED NO_RETURN PARTIAL_RETURN VOID_RETURN VALUE_RETURN THROW */
64     /* NOT_POSSIBLE */ { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE },
65     /* UNDEFINED */ { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
66     /* NO_RETURN */ { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NO_RETURN },
67     /* PARTIAL_RETURN */ { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN },
68     /* VOID_RETURN */ { NOT_POSSIBLE, VOID_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, VOID_RETURN },
69     /* VALUE_RETURN */ { NOT_POSSIBLE, VALUE_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN },
70     /* THROW */ { NOT_POSSIBLE, THROW, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }
71     };
72         
73     // Table to merge return modes for sequential statements (y: fReturnKind, x: other.fReturnKind)
74
private static final int[][] RETURN_KIND_SEQUENTIAL_TABLE = {
75     /* NOT_POSSIBLE UNDEFINED NO_RETURN PARTIAL_RETURN VOID_RETURN VALUE_RETURN THROW */
76     /* NOT_POSSIBLE */ { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE },
77     /* UNDEFINED */ { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
78     /* NO_RETURN */ { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
79     /* PARTIAL_RETURN */ { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW },
80     /* VOID_RETURN */ { NOT_POSSIBLE, VOID_RETURN, VOID_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, NOT_POSSIBLE },
81     /* VALUE_RETURN */ { NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, NOT_POSSIBLE },
82     /* THROW */ { NOT_POSSIBLE, THROW, THROW, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }
83     };
84         
85     protected static final String JavaDoc UNLABELED = "@unlabeled"; //$NON-NLS-1$
86
protected static final IVariableBinding[] EMPTY_ARRAY= new IVariableBinding[0];
87
88     protected int fReturnKind;
89     protected int[] fAccessModes;
90     protected Set JavaDoc fBranches;
91     protected Set JavaDoc fExceptions;
92     protected Set JavaDoc fTypeVariables;
93     
94     protected FlowInfo() {
95         this(UNDEFINED);
96     }
97     
98     protected FlowInfo(int returnKind) {
99         fReturnKind= returnKind;
100     }
101     
102     //---- General Helpers ----------------------------------------------------------
103

104     protected void assignExecutionFlow(FlowInfo right) {
105         fReturnKind= right.fReturnKind;
106         fBranches= right.fBranches;
107         fExceptions= right.fExceptions;
108     }
109     
110     protected void assignAccessMode(FlowInfo right) {
111         fAccessModes= right.fAccessModes;
112     }
113     
114     protected void assign(FlowInfo right) {
115         assignExecutionFlow(right);
116         assignAccessMode(right);
117     }
118     
119     protected void mergeConditional(FlowInfo info, FlowContext context) {
120         mergeAccessModeConditional(info, context);
121         mergeExecutionFlowConditional(info, context);
122         mergeTypeVariablesConditional(info, context);
123     }
124     
125     protected void mergeSequential(FlowInfo info, FlowContext context) {
126         mergeAccessModeSequential(info, context);
127         mergeExecutionFlowSequential(info, context);
128         mergeTypeVariablesSequential(info, context);
129     }
130     
131     //---- Return Kind ------------------------------------------------------------------
132

133     public void setNoReturn() {
134         fReturnKind= NO_RETURN;
135     }
136     
137     public boolean isUndefined() {
138         return fReturnKind == UNDEFINED;
139     }
140     
141     public boolean isNoReturn() {
142         return fReturnKind == NO_RETURN;
143     }
144     
145     public boolean isPartialReturn() {
146         return fReturnKind == PARTIAL_RETURN;
147     }
148     
149     public boolean isVoidReturn() {
150         return fReturnKind == VOID_RETURN;
151     }
152     
153     public boolean isValueReturn() {
154         return fReturnKind == VALUE_RETURN;
155     }
156     
157     public boolean isThrow() {
158         return fReturnKind == THROW;
159     }
160
161     public boolean isReturn() {
162         return fReturnKind == VOID_RETURN || fReturnKind == VALUE_RETURN;
163     }
164     
165     //---- Branches -------------------------------------------------------------------------
166

167     public boolean branches() {
168         return fBranches != null && !fBranches.isEmpty();
169     }
170     
171     protected Set JavaDoc getBranches() {
172         return fBranches;
173     }
174     
175     protected void removeLabel(SimpleName label) {
176         if (fBranches != null) {
177             fBranches.remove(makeString(label));
178             if (fBranches.isEmpty())
179                 fBranches= null;
180         }
181     }
182     
183     protected static String JavaDoc makeString(SimpleName label) {
184         if (label == null)
185             return UNLABELED;
186         else
187             return label.getIdentifier();
188     }
189     
190     //---- Exceptions -----------------------------------------------------------------------
191

192     public ITypeBinding[] getExceptions() {
193         if (fExceptions == null)
194             return new ITypeBinding[0];
195         return (ITypeBinding[]) fExceptions.toArray(new ITypeBinding[fExceptions.size()]);
196     }
197
198     protected boolean hasUncaughtException() {
199         return fExceptions != null && !fExceptions.isEmpty();
200     }
201     
202     protected void addException(ITypeBinding type) {
203         if (fExceptions == null)
204             fExceptions= new HashSet JavaDoc(2);
205         fExceptions.add(type);
206     }
207     
208     protected void removeExceptions(TryStatement node) {
209         if (fExceptions == null)
210             return;
211             
212         List JavaDoc catchClauses= node.catchClauses();
213         if (catchClauses.isEmpty())
214             return;
215         // Make sure we have a copy since we are modifing the fExceptions list
216
ITypeBinding[] exceptions= (ITypeBinding[]) fExceptions.toArray(new ITypeBinding[fExceptions.size()]);
217         for (int i= 0; i < exceptions.length; i++) {
218             handleException(catchClauses, exceptions[i]);
219         }
220         if (fExceptions.isEmpty())
221             fExceptions= null;
222     }
223
224     private void handleException(List JavaDoc catchClauses, ITypeBinding type) {
225         for (Iterator JavaDoc iter= catchClauses.iterator(); iter.hasNext();) {
226             IVariableBinding binding= ((CatchClause)iter.next()).getException().resolveBinding();
227             if (binding == null)
228                 continue;
229             ITypeBinding catchedType= binding.getType();
230             while (catchedType != null) {
231                 if (catchedType == type) {
232                     fExceptions.remove(type);
233                     return;
234                 }
235                 catchedType= catchedType.getSuperclass();
236             }
237         }
238     }
239     
240     //---- Type parameters -----------------------------------------------------------------
241

242     public ITypeBinding[] getTypeVariables() {
243         if (fTypeVariables == null)
244             return new ITypeBinding[0];
245         return (ITypeBinding[])fTypeVariables.toArray(new ITypeBinding[fTypeVariables.size()]);
246     }
247     
248     protected void addTypeVariable(ITypeBinding typeParameter) {
249         if (fTypeVariables == null)
250             fTypeVariables= new HashSet JavaDoc();
251         fTypeVariables.add(typeParameter);
252     }
253     
254     private void mergeTypeVariablesSequential(FlowInfo otherInfo, FlowContext context) {
255         fTypeVariables= mergeSets(fTypeVariables, otherInfo.fTypeVariables);
256     }
257     
258     private void mergeTypeVariablesConditional(FlowInfo otherInfo, FlowContext context) {
259         fTypeVariables= mergeSets(fTypeVariables, otherInfo.fTypeVariables);
260     }
261     
262     //---- Execution flow -------------------------------------------------------------------
263

264     private void mergeExecutionFlowSequential(FlowInfo otherInfo, FlowContext context) {
265         int other= otherInfo.fReturnKind;
266         if (branches() && other == VALUE_RETURN)
267             other= PARTIAL_RETURN;
268         fReturnKind= RETURN_KIND_SEQUENTIAL_TABLE[fReturnKind][other];
269         mergeBranches(otherInfo, context);
270         mergeExceptions(otherInfo, context);
271     }
272     
273     private void mergeExecutionFlowConditional(FlowInfo otherInfo, FlowContext context) {
274         fReturnKind= RETURN_KIND_CONDITIONAL_TABLE[fReturnKind][otherInfo.fReturnKind];
275         mergeBranches(otherInfo, context);
276         mergeExceptions(otherInfo, context);
277     }
278     
279     private void mergeBranches(FlowInfo otherInfo, FlowContext context) {
280         fBranches= mergeSets(fBranches, otherInfo.fBranches);
281     }
282
283     private void mergeExceptions(FlowInfo otherInfo, FlowContext context) {
284         fExceptions= mergeSets(fExceptions, otherInfo.fExceptions);
285     }
286     
287     private static Set JavaDoc mergeSets(Set JavaDoc thisSet, Set JavaDoc otherSet) {
288         if (otherSet != null) {
289             if (thisSet == null) {
290                 thisSet= otherSet;
291             } else {
292                 Iterator JavaDoc iter= otherSet.iterator();
293                 while (iter.hasNext()) {
294                     thisSet.add(iter.next());
295                 }
296             }
297         }
298         return thisSet;
299     }
300     
301     //---- Local access handling --------------------------------------------------
302

303     /**
304      * Returns an array of <code>IVariableBinding</code> that conform to the given
305      * access mode <code>mode</code>.
306      *
307      * @param context the flow context object used to compute this flow info
308      * @param mode the access type. Valid values are <code>READ</code>, <code>WRITE</code>,
309      * <code>UNKNOWN</code> and any combination of them.
310      * @return an array of local variable bindings conforming to the given type.
311      */

312     public IVariableBinding[] get(FlowContext context, int mode) {
313         List JavaDoc result= new ArrayList JavaDoc();
314         int[] locals= getAccessModes();
315         if (locals == null)
316             return EMPTY_ARRAY;
317         for (int i= 0; i < locals.length; i++) {
318             int accessMode= locals[i];
319             if ((accessMode & mode) != 0)
320                 result.add(context.getLocalFromIndex(i));
321         }
322         return (IVariableBinding[])result.toArray(new IVariableBinding[result.size()]);
323     }
324     
325     /**
326      * Checks whether the given local variable binding has the given access
327      * mode.
328      *
329      * @return <code>true</code> if the binding has the given access mode.
330      * <code>False</code> otherwise
331      */

332     public boolean hasAccessMode(FlowContext context, IVariableBinding local, int mode) {
333         boolean unusedMode= (mode & UNUSED) != 0;
334         if (fAccessModes == null && unusedMode)
335             return true;
336         int index= context.getIndexFromLocal(local);
337         if (index == -1)
338             return unusedMode;
339         return (fAccessModes[index] & mode) != 0;
340     }
341     
342     /**
343      * Returns the access mode of the local variable identified by the given binding.
344      *
345      * @param context the flow context used during flow analysis
346      * @param local the local variable of interest
347      * @return the access mode of the local variable
348      */

349     public int getAccessMode(FlowContext context, IVariableBinding local) {
350         if (fAccessModes == null)
351             return UNUSED;
352         int index= context.getIndexFromLocal(local);
353         if (index == -1)
354             return UNUSED;
355         return fAccessModes[index];
356     }
357     
358     protected int[] getAccessModes() {
359         return fAccessModes;
360     }
361     
362     protected void clearAccessMode(IVariableBinding binding, FlowContext context) {
363         if (fAccessModes == null) // all are unused
364
return;
365         fAccessModes[binding.getVariableId() - context.getStartingIndex()]= UNUSED;
366     }
367     
368     protected void mergeAccessModeSequential(FlowInfo otherInfo, FlowContext context) {
369         if (!context.considerAccessMode())
370             return;
371         
372         int[] others= otherInfo.fAccessModes;
373         if (others == null) // others are all unused. So nothing to do
374
return;
375             
376         // Must not consider return kind since a return statement can't control execution flow
377
// inside a method. It always leaves the method.
378
if (branches() || hasUncaughtException()) {
379             for (int i= 0; i < others.length; i++)
380                 others[i]= ACCESS_MODE_OPEN_BRANCH_TABLE[getIndex(others[i])];
381         }
382         
383         if (fAccessModes == null) { // all current variables are unused
384
fAccessModes= others;
385             return;
386         }
387         
388         if (context.computeArguments()) {
389             handleComputeArguments(others);
390         } else if (context.computeReturnValues()) {
391             handleComputeReturnValues(others);
392         } else if (context.computeMerge()) {
393             handleMergeValues(others);
394         }
395     }
396
397     private void handleComputeReturnValues(int[] others) {
398         for (int i= 0; i < fAccessModes.length; i++) {
399             int accessmode= fAccessModes[i];
400             int othermode= others[i];
401             if (accessmode == WRITE)
402                 continue;
403             if (accessmode == WRITE_POTENTIAL) {
404                 if (othermode == WRITE)
405                     fAccessModes[i]= WRITE;
406                 continue;
407             }
408         
409             if (others[i] != UNUSED)
410                 fAccessModes[i]= othermode;
411         }
412     }
413
414     private void handleComputeArguments(int[] others) {
415         for (int i= 0; i < fAccessModes.length; i++) {
416             int accessMode= fAccessModes[i];
417             int otherMode= others[i];
418             if (accessMode == UNUSED) {
419                 fAccessModes[i]= otherMode;
420             } else if (accessMode == WRITE_POTENTIAL && (otherMode == READ || otherMode == READ_POTENTIAL)) {
421                 // Read always supersedes a potential write even if the read is potential as well
422
// (we have to consider the potential read as an argument then).
423
fAccessModes[i]= otherMode;
424             } else if (accessMode == WRITE_POTENTIAL && otherMode == WRITE) {
425                 fAccessModes[i]= WRITE;
426             }
427         }
428     }
429     
430     private void handleMergeValues(int[] others) {
431         for (int i= 0; i < fAccessModes.length; i++) {
432             fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
433                 [getIndex(fAccessModes[i])]
434                 [getIndex(others[i])];
435         }
436     }
437     
438     protected void createAccessModeArray(FlowContext context) {
439         fAccessModes= new int[context.getArrayLength()];
440         for (int i= 0; i < fAccessModes.length; i++) {
441             fAccessModes[i]= UNUSED;
442         }
443     }
444     
445     protected void mergeAccessModeConditional(FlowInfo otherInfo, FlowContext context) {
446         if (!context.considerAccessMode())
447             return;
448         
449         int[] others= otherInfo.fAccessModes;
450         // first access
451
if (fAccessModes == null) {
452             if (others != null)
453                 fAccessModes= others;
454             else
455                 createAccessModeArray(context);
456             return;
457         } else {
458             if (others == null) {
459                 for (int i= 0; i < fAccessModes.length; i++) {
460                     int unused_index= getIndex(UNUSED);
461                     fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
462                         [getIndex(fAccessModes[i])]
463                         [unused_index];
464                 }
465             } else {
466                 for (int i= 0; i < fAccessModes.length; i++) {
467                     fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
468                         [getIndex(fAccessModes[i])]
469                         [getIndex(others[i])];
470                 }
471             }
472         }
473     }
474     
475     protected void mergeEmptyCondition(FlowContext context) {
476         if (fReturnKind == VALUE_RETURN || fReturnKind == VOID_RETURN)
477             fReturnKind= PARTIAL_RETURN;
478             
479         if (!context.considerAccessMode())
480             return;
481             
482         if (fAccessModes == null) {
483             createAccessModeArray(context);
484             return;
485         }
486         
487         int unused_index= getIndex(UNUSED);
488         for (int i= 0; i < fAccessModes.length; i++) {
489             fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
490                 [getIndex(fAccessModes[i])]
491                 [unused_index];
492         }
493     }
494     
495     private static int getIndex(int accessMode) {
496          // Fast log function
497
switch (accessMode) {
498             case UNUSED:
499                 return 0;
500             case READ:
501                 return 1;
502             case READ_POTENTIAL:
503                 return 2;
504             case WRITE:
505                 return 3;
506             case WRITE_POTENTIAL:
507                 return 4;
508             case UNKNOWN:
509                 return 5;
510          }
511          return -1;
512     }
513 }
514
515
516
Popular Tags