]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/FlowInfo.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / core refactoring / org / eclipse / jdt / internal / corext / refactoring / code / flow / FlowInfo.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2011 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  *     Benjamin Muskalla <bmuskalla@eclipsesource.com> - [extract method] missing return type when code can throw exception - https://bugs.eclipse.org/bugs/show_bug.cgi?id=97413
11  *******************************************************************************/
12 package org.eclipse.jdt.internal.corext.refactoring.code.flow;
13
14 import java.util.ArrayList;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Set;
19
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
24 import org.eclipse.jdt.internal.corext.refactoring.code.ExtractMethodAnalyzer;
25
26 public abstract class FlowInfo {
27
28         // Return statement handling.
29         protected static final int NOT_POSSIBLE=        0;
30         protected static final int UNDEFINED=           1;
31         protected static final int NO_RETURN=           2;
32         protected static final int PARTIAL_RETURN=      3;
33         protected static final int VOID_RETURN=         4;
34         protected static final int VALUE_RETURN=        5;
35         protected static final int THROW=                       6;
36
37         // Local access handling.
38         public static final int UNUSED=                         1 << 0;
39         public static final int READ=                           1 << 1;
40         public static final int READ_POTENTIAL=         1 << 2;
41         public static final int WRITE=                          1 << 3;
42         public static final int WRITE_POTENTIAL=    1 << 4;
43         public static final int UNKNOWN=                        1 << 5;
44
45         // Table to merge access modes for condition statements (e.g branch[x] || branch[y]).
46         private static final int[][] ACCESS_MODE_CONDITIONAL_TABLE= {
47         /*                                                UNUSED                   READ                     READ_POTENTIAL   WRTIE                        WRITE_POTENTIAL  UNKNOWN */
48         /* UNUSED */                    { UNUSED,                  READ_POTENTIAL,  READ_POTENTIAL,  WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
49         /* READ */                              { READ_POTENTIAL,  READ,                        READ_POTENTIAL,  UNKNOWN,                 UNKNOWN,         UNKNOWN },
50         /* READ_POTENTIAL */    { READ_POTENTIAL,  READ_POTENTIAL,  READ_POTENTIAL,  UNKNOWN,             UNKNOWN,         UNKNOWN },
51         /* WRITE */                             { WRITE_POTENTIAL, UNKNOWN,                     UNKNOWN,                 WRITE,                   WRITE_POTENTIAL, UNKNOWN },
52         /* WRITE_POTENTIAL */   { WRITE_POTENTIAL, UNKNOWN,                     UNKNOWN,                 WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN },
53         /* UNKNOWN */                   { UNKNOWN,                 UNKNOWN,                     UNKNOWN,                 UNKNOWN,                 UNKNOWN,                 UNKNOWN }
54         };
55
56         // Table to change access mode if there is an open branch statement
57         private static final int[] ACCESS_MODE_OPEN_BRANCH_TABLE= {
58         /*      UNUSED  READ                    READ_POTENTIAL  WRTIE                           WRITE_POTENTIAL  UNKNOWN */
59                 UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL,        WRITE_POTENTIAL, UNKNOWN
60         };
61
62         // Table to merge return modes for condition statements (y: fReturnKind, x: other.fReturnKind)
63         private static final int[][] RETURN_KIND_CONDITIONAL_TABLE = {
64         /*                                                NOT_POSSIBLE          UNDEFINED               NO_RETURN               PARTIAL_RETURN  VOID_RETURN             VALUE_RETURN    THROW */
65         /* NOT_POSSIBLE */              { NOT_POSSIBLE,         NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE    },
66         /* UNDEFINED */                 { NOT_POSSIBLE,         UNDEFINED,              NO_RETURN,              PARTIAL_RETURN, VOID_RETURN,    VALUE_RETURN,   THROW                   },
67         /* NO_RETURN */                 { NOT_POSSIBLE,         NO_RETURN,              NO_RETURN,              PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NO_RETURN               },
68         /* PARTIAL_RETURN */    { NOT_POSSIBLE,         PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN  },
69         /* VOID_RETURN */               { NOT_POSSIBLE,         VOID_RETURN,    PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN,    NOT_POSSIBLE,   VOID_RETURN             },
70         /* VALUE_RETURN */              { NOT_POSSIBLE,         VALUE_RETURN,   PARTIAL_RETURN, PARTIAL_RETURN, NOT_POSSIBLE,   VALUE_RETURN,   VALUE_RETURN    },
71         /* THROW */                             { NOT_POSSIBLE,         THROW,                  NO_RETURN,              PARTIAL_RETURN, VOID_RETURN,    VALUE_RETURN,   THROW                   }
72         };
73
74         // Table to merge return modes for sequential statements (y: fReturnKind, x: other.fReturnKind)
75         private static final int[][] RETURN_KIND_SEQUENTIAL_TABLE = {
76         /*                                                NOT_POSSIBLE          UNDEFINED               NO_RETURN               PARTIAL_RETURN  VOID_RETURN             VALUE_RETURN    THROW */
77         /* NOT_POSSIBLE */              { NOT_POSSIBLE,         NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE,   NOT_POSSIBLE    },
78         /* UNDEFINED */                 { NOT_POSSIBLE,         UNDEFINED,              NO_RETURN,              PARTIAL_RETURN, VOID_RETURN,    VALUE_RETURN,   THROW                   },
79         /* NO_RETURN */                 { NOT_POSSIBLE,         NO_RETURN,              NO_RETURN,              PARTIAL_RETURN, VOID_RETURN,    VALUE_RETURN,   THROW                   },
80         /* PARTIAL_RETURN */    { NOT_POSSIBLE,         PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN,    VALUE_RETURN,   VALUE_RETURN    },
81         /* VOID_RETURN */               { NOT_POSSIBLE,         VOID_RETURN,    VOID_RETURN,    PARTIAL_RETURN, VOID_RETURN,    NOT_POSSIBLE,   NOT_POSSIBLE    },
82         /* VALUE_RETURN */              { NOT_POSSIBLE,         VALUE_RETURN,   VALUE_RETURN,   PARTIAL_RETURN, NOT_POSSIBLE,   VALUE_RETURN,   NOT_POSSIBLE    },
83         /* THROW */                             { NOT_POSSIBLE,         THROW,                  THROW,                  VALUE_RETURN,   VOID_RETURN,    VALUE_RETURN,   THROW                   }
84         };
85
86         protected static final String UNLABELED = "@unlabeled"; //$NON-NLS-1$
87         protected static final IVariableBinding[] EMPTY_ARRAY= new IVariableBinding[0];
88
89         protected int fReturnKind;
90         protected int[] fAccessModes;
91         protected Set<String> fBranches;
92         //protected Set<ITypeBinding> fExceptions;
93         protected Set<ITypeBinding> fTypeVariables;
94
95         protected FlowInfo() {
96                 this(UNDEFINED);
97         }
98
99         protected FlowInfo(int returnKind) {
100                 fReturnKind= returnKind;
101         }
102
103         //---- General Helpers ----------------------------------------------------------
104
105         protected void assignExecutionFlow(FlowInfo right) {
106                 right.generated_5909308445650589946(this);
107         }
108
109         protected void assignAccessMode(FlowInfo right) {
110                 right.generated_2737604558401151346(this);
111         }
112
113         protected void assign(FlowInfo right) {
114                 assignExecutionFlow(right);
115                 assignAccessMode(right);
116         }
117
118         protected void mergeConditional(FlowInfo info, FlowContext context) {
119                 mergeAccessModeConditional(info, context);
120                 info.generated_4203786444310502274(this);
121         }
122
123         protected void mergeSequential(FlowInfo info, FlowContext context) {
124                 mergeAccessModeSequential(info, context);
125                 info.generated_5384924323028097289(this);
126         }
127
128         
129
130         //---- Return Kind ------------------------------------------------------------------
131
132         public void setNoReturn() {
133                 fReturnKind= NO_RETURN;
134         }
135
136         public boolean isUndefined() {
137                 return fReturnKind == UNDEFINED;
138         }
139
140         public boolean isNoReturn() {
141                 return fReturnKind == NO_RETURN;
142         }
143
144         public boolean isPartialReturn() {
145                 return fReturnKind == PARTIAL_RETURN;
146         }
147
148         public boolean isVoidReturn() {
149                 return fReturnKind == VOID_RETURN;
150         }
151
152         public boolean isValueReturn() {
153                 return fReturnKind == VALUE_RETURN;
154         }
155
156         public boolean isThrow() {
157                 return fReturnKind == THROW;
158         }
159
160         public boolean isReturn() {
161                 return fReturnKind == VOID_RETURN || fReturnKind == VALUE_RETURN;
162         }
163
164         //---- Branches -------------------------------------------------------------------------
165
166         public boolean branches() {
167                 return fBranches != null && !fBranches.isEmpty();
168         }
169
170         protected Set<String> getBranches() {
171                 return fBranches;
172         }
173
174         protected void removeLabel(SimpleName label) {
175                 if (fBranches != null) {
176                         fBranches.remove(makeString(label));
177                         if (fBranches.isEmpty())
178                                 fBranches= null;
179                 }
180         }
181
182         protected static String makeString(SimpleName label) {
183                 if (label == null)
184                         return UNLABELED;
185                 else
186                         return label.getIdentifier();
187         }
188
189         //---- Type parameters -----------------------------------------------------------------
190
191         public ITypeBinding[] getTypeVariables() {
192                 if (fTypeVariables == null)
193                         return new ITypeBinding[0];
194                 return fTypeVariables.toArray(new ITypeBinding[fTypeVariables.size()]);
195         }
196
197         protected void addTypeVariable(ITypeBinding typeParameter) {
198                 if (fTypeVariables == null)
199                         fTypeVariables= new HashSet<ITypeBinding>();
200                 fTypeVariables.add(typeParameter);
201         }
202
203         private void mergeTypeVariablesSequential(FlowInfo otherInfo) {
204                 otherInfo.generated_9177087240118677719(this);
205         }
206
207         private void mergeTypeVariablesConditional(FlowInfo otherInfo) {
208                 otherInfo.generated_3576989528696038545(this);
209         }
210
211         
212
213         //---- Execution flow -------------------------------------------------------------------
214
215         private void mergeExecutionFlowSequential(FlowInfo otherInfo) {
216                 otherInfo.generated_1782832635089041599(this);
217         }
218
219         private void mergeExecutionFlowConditional(FlowInfo otherInfo) {
220                 otherInfo.generated_8403552546052715200(this);
221         }
222
223         private void mergeBranches(FlowInfo otherInfo) {
224                 otherInfo.generated_1347106970305352130(this);
225         }
226
227         private static <T> Set<T> mergeSets(Set<T> thisSet, Set<T> otherSet) {
228                 if (otherSet != null) {
229                         if (thisSet == null) {
230                                 thisSet= otherSet;
231                         } else {
232                                 Iterator<T> iter= otherSet.iterator();
233                                 while (iter.hasNext()) {
234                                         thisSet.add(iter.next());
235                                 }
236                         }
237                 }
238                 return thisSet;
239         }
240
241         //---- Local access handling --------------------------------------------------
242
243         /**
244          * Returns an array of <code>IVariableBinding</code> that conform to the given
245          * access mode <code>mode</code>.
246          *
247          * @param context the flow context object used to compute this flow info
248          * @param mode the access type. Valid values are <code>READ</code>, <code>WRITE</code>,
249          *  <code>UNKNOWN</code> and any combination of them.
250          * @return an array of local variable bindings conforming to the given type.
251          */
252         public IVariableBinding[] get(FlowContext context, int mode) {
253                 List<IVariableBinding> result= new ArrayList<IVariableBinding>();
254                 int[] locals= getAccessModes();
255                 if (locals == null)
256                         return EMPTY_ARRAY;
257                 for (int i= 0; i < locals.length; i++) {
258                         int accessMode= locals[i];
259                         if ((accessMode & mode) != 0)
260                                 result.add(context.getLocalFromIndex(i));
261                 }
262                 return result.toArray(new IVariableBinding[result.size()]);
263         }
264
265         /**
266          * Checks whether the given local variable binding has the given access
267          * mode.
268          * 
269          * @param context the flow context used during flow analysis
270          * @param local local variable of interest
271          * @param mode the access mode of the local variable
272          *
273          * @return <code>true</code> if the binding has the given access mode.
274          *      <code>False</code> otherwise
275          */
276         public boolean hasAccessMode(FlowContext context, IVariableBinding local, int mode) {
277                 boolean unusedMode= (mode & UNUSED) != 0;
278                 if (fAccessModes == null && unusedMode)
279                         return true;
280                 int index= context.getIndexFromLocal(local);
281                 if (index == -1)
282                         return unusedMode;
283                 return (fAccessModes[index] & mode) != 0;
284         }
285
286         /**
287          * Returns the access mode of the local variable identified by the given binding.
288          *
289          * @param context the flow context used during flow analysis
290          * @param local the local variable of interest
291          * @return the access mode of the local variable
292          */
293         public int getAccessMode(FlowContext context, IVariableBinding local) {
294                 if (fAccessModes == null)
295                         return UNUSED;
296                 int index= context.getIndexFromLocal(local);
297                 if (index == -1)
298                         return UNUSED;
299                 return fAccessModes[index];
300         }
301
302         protected int[] getAccessModes() {
303                 return fAccessModes;
304         }
305
306         protected void clearAccessMode(IVariableBinding binding, FlowContext context) {
307                 if (fAccessModes == null)       // all are unused
308                         return;
309                 fAccessModes[binding.getVariableId() - context.getStartingIndex()]= UNUSED;
310         }
311
312         protected void mergeAccessModeSequential(FlowInfo otherInfo, FlowContext context) {
313                 if (!context.considerAccessMode())
314                         return;
315
316                 int[] others= otherInfo.generated_8026203182823550563(this);
317                 if (others == null)     // others are all unused. So nothing to do
318                         return;
319
320                 // Must not consider return kind since a return statement can't control execution flow
321                 // inside a method. It always leaves the method.
322                 if (branches()) {
323                         for (int i= 0; i < others.length; i++)
324                                 others[i]= ACCESS_MODE_OPEN_BRANCH_TABLE[getIndex(others[i])];
325                 }
326
327                 if (fAccessModes == null) {     // all current variables are unused
328                         fAccessModes= others;
329                         return;
330                 }
331
332                 if (context.computeArguments()) {
333                         handleComputeArguments(others);
334                 } else if (context.computeReturnValues()) {
335                         handleComputeReturnValues(others);
336                 } else if (context.computeMerge()) {
337                         handleMergeValues(others);
338                 }
339         }
340
341         private void handleComputeReturnValues(int[] others) {
342                 for (int i= 0; i < fAccessModes.length; i++) {
343                         int accessmode= fAccessModes[i];
344                         int othermode= others[i];
345                         if (accessmode == WRITE)
346                                 continue;
347                         if (accessmode == WRITE_POTENTIAL) {
348                                 if (othermode == WRITE)
349                                         fAccessModes[i]= WRITE;
350                                 continue;
351                         }
352
353                         if (others[i] != UNUSED)
354                                 fAccessModes[i]= othermode;
355                 }
356         }
357
358         private void handleComputeArguments(int[] others) {
359                 for (int i= 0; i < fAccessModes.length; i++) {
360                         int accessMode= fAccessModes[i];
361                         int otherMode= others[i];
362                         if (accessMode == UNUSED) {
363                                 fAccessModes[i]= otherMode;
364                         } else if (accessMode == WRITE_POTENTIAL && (otherMode == READ || otherMode == READ_POTENTIAL)) {
365                                 // Read always supersedes a potential write even if the read is potential as well
366                                 // (we have to consider the potential read as an argument then).
367                                 fAccessModes[i]= otherMode;
368                         } else if (accessMode == WRITE_POTENTIAL && otherMode == WRITE) {
369                                 fAccessModes[i]= WRITE;
370                         }
371                 }
372         }
373
374         private void handleMergeValues(int[] others) {
375                 for (int i= 0; i < fAccessModes.length; i++) {
376                         fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
377                                 [getIndex(fAccessModes[i])]
378                                 [getIndex(others[i])];
379                 }
380         }
381
382         protected void createAccessModeArray(FlowContext context) {
383                 fAccessModes= new int[context.getArrayLength()];
384                 for (int i= 0; i < fAccessModes.length; i++) {
385                         fAccessModes[i]= UNUSED;
386                 }
387         }
388
389         protected void mergeAccessModeConditional(FlowInfo otherInfo, FlowContext context) {
390                 if (!context.considerAccessMode())
391                         return;
392
393                 int[] others= otherInfo.generated_2805630759121218078(this);
394                 // first access
395                 if (fAccessModes == null) {
396                         if (others != null)
397                                 fAccessModes= others;
398                         else
399                                 createAccessModeArray(context);
400                         return;
401                 } else {
402                         if (others == null) {
403                                 for (int i= 0; i < fAccessModes.length; i++) {
404                                         int unused_index= getIndex(UNUSED);
405                                         fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
406                                                 [getIndex(fAccessModes[i])]
407                                                 [unused_index];
408                                 }
409                         } else {
410                                 for (int i= 0; i < fAccessModes.length; i++) {
411                                         fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
412                                                 [getIndex(fAccessModes[i])]
413                                                 [getIndex(others[i])];
414                                 }
415                         }
416                 }
417         }
418
419         protected void mergeEmptyCondition(FlowContext context) {
420                 if (fReturnKind == VALUE_RETURN || fReturnKind == VOID_RETURN)
421                         fReturnKind= PARTIAL_RETURN;
422
423                 if (!context.considerAccessMode())
424                         return;
425
426                 if (fAccessModes == null) {
427                         createAccessModeArray(context);
428                         return;
429                 }
430
431                 int unused_index= getIndex(UNUSED);
432                 for (int i= 0; i < fAccessModes.length; i++) {
433                         fAccessModes[i]= ACCESS_MODE_CONDITIONAL_TABLE
434                                 [getIndex(fAccessModes[i])]
435                                 [unused_index];
436                 }
437         }
438
439         public void generated_3658011097861187265(ExtractMethodAnalyzer extractmethodanalyzer) {
440                 extractmethodanalyzer.fMethodLocals= extractmethodanalyzer.removeSelectedDeclarations(get(extractmethodanalyzer.fInputFlowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL));
441                 extractmethodanalyzer.fTypeVariables= extractmethodanalyzer.computeTypeVariables(getTypeVariables());
442         }
443
444         public void generated_5909308445650589946(FlowInfo flowinfo) {
445                 flowinfo.fReturnKind= fReturnKind;
446                 flowinfo.fBranches= fBranches;
447         }
448
449         public void generated_2737604558401151346(FlowInfo flowinfo) {
450                 flowinfo.fAccessModes= fAccessModes;
451         }
452
453         public void generated_4203786444310502274(FlowInfo flowinfo) {
454                 flowinfo.mergeExecutionFlowConditional(this);
455                 flowinfo.mergeTypeVariablesConditional(this);
456         }
457
458         public void generated_5384924323028097289(FlowInfo flowinfo) {
459                 flowinfo.mergeExecutionFlowSequential(this);
460                 flowinfo.mergeTypeVariablesSequential(this);
461         }
462
463         public void generated_9177087240118677719(FlowInfo flowinfo) {
464                 flowinfo.fTypeVariables= FlowInfo.mergeSets(flowinfo.fTypeVariables, fTypeVariables);
465         }
466
467         public void generated_3576989528696038545(FlowInfo flowinfo) {
468                 flowinfo.fTypeVariables= FlowInfo.mergeSets(flowinfo.fTypeVariables, fTypeVariables);
469         }
470
471         public void generated_1782832635089041599(FlowInfo flowinfo) {
472                 int other= fReturnKind;
473                 if (flowinfo.branches() && other == FlowInfo.VALUE_RETURN)
474                         other= FlowInfo.PARTIAL_RETURN;
475                 flowinfo.fReturnKind= FlowInfo.RETURN_KIND_SEQUENTIAL_TABLE[flowinfo.fReturnKind][other];
476                 flowinfo.mergeBranches(this);
477         }
478
479         public void generated_8403552546052715200(FlowInfo flowinfo) {
480                 flowinfo.fReturnKind= FlowInfo.RETURN_KIND_CONDITIONAL_TABLE[flowinfo.fReturnKind][fReturnKind];
481                 flowinfo.mergeBranches(this);
482         }
483
484         public void generated_1347106970305352130(FlowInfo flowinfo) {
485                 flowinfo.fBranches= FlowInfo.mergeSets(flowinfo.fBranches, fBranches);
486         }
487
488         public int[] generated_8026203182823550563(FlowInfo flowinfo) {
489                 int[] others= fAccessModes;
490                 return others;
491         }
492
493         public int[] generated_2805630759121218078(FlowInfo flowinfo) {
494                 int[] others= fAccessModes;
495                 return others;
496         }
497
498         private static int getIndex(int accessMode) {
499                  // Fast log function
500                  switch (accessMode) {
501                         case UNUSED:
502                                 return 0;
503                         case READ:
504                                 return 1;
505                         case READ_POTENTIAL:
506                                 return 2;
507                         case WRITE:
508                                 return 3;
509                         case WRITE_POTENTIAL:
510                                 return 4;
511                         case UNKNOWN:
512                                 return 5;
513                  }
514                  return -1;
515         }
516 }
517
518