1 11 package org.eclipse.jdt.internal.corext.refactoring.code.flow; 12 13 import java.util.ArrayList ; 14 import java.util.HashSet ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Set ; 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 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 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 private static final int[][] ACCESS_MODE_CONDITIONAL_TABLE= { 46 47 { UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN }, 48 { READ_POTENTIAL, READ, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN }, 49 { READ_POTENTIAL, READ_POTENTIAL, READ_POTENTIAL, UNKNOWN, UNKNOWN, UNKNOWN }, 50 { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE, WRITE_POTENTIAL, UNKNOWN }, 51 { WRITE_POTENTIAL, UNKNOWN, UNKNOWN, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN }, 52 { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN } 53 }; 54 55 private static final int[] ACCESS_MODE_OPEN_BRANCH_TABLE= { 57 58 UNUSED, READ_POTENTIAL, READ_POTENTIAL, WRITE_POTENTIAL, WRITE_POTENTIAL, UNKNOWN 59 }; 60 61 private static final int[][] RETURN_KIND_CONDITIONAL_TABLE = { 63 64 { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE }, 65 { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }, 66 { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NO_RETURN }, 67 { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN }, 68 { NOT_POSSIBLE, VOID_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, VOID_RETURN }, 69 { NOT_POSSIBLE, VALUE_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN }, 70 { NOT_POSSIBLE, THROW, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW } 71 }; 72 73 private static final int[][] RETURN_KIND_SEQUENTIAL_TABLE = { 75 76 { NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE, NOT_POSSIBLE }, 77 { NOT_POSSIBLE, UNDEFINED, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }, 78 { NOT_POSSIBLE, NO_RETURN, NO_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }, 79 { NOT_POSSIBLE, PARTIAL_RETURN, PARTIAL_RETURN, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW }, 80 { NOT_POSSIBLE, VOID_RETURN, VOID_RETURN, PARTIAL_RETURN, VOID_RETURN, NOT_POSSIBLE, NOT_POSSIBLE }, 81 { NOT_POSSIBLE, VALUE_RETURN, VALUE_RETURN, PARTIAL_RETURN, NOT_POSSIBLE, VALUE_RETURN, NOT_POSSIBLE }, 82 { NOT_POSSIBLE, THROW, THROW, PARTIAL_RETURN, VOID_RETURN, VALUE_RETURN, THROW } 83 }; 84 85 protected static final String UNLABELED = "@unlabeled"; protected static final IVariableBinding[] EMPTY_ARRAY= new IVariableBinding[0]; 87 88 protected int fReturnKind; 89 protected int[] fAccessModes; 90 protected Set fBranches; 91 protected Set fExceptions; 92 protected Set fTypeVariables; 93 94 protected FlowInfo() { 95 this(UNDEFINED); 96 } 97 98 protected FlowInfo(int returnKind) { 99 fReturnKind= returnKind; 100 } 101 102 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 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 167 public boolean branches() { 168 return fBranches != null && !fBranches.isEmpty(); 169 } 170 171 protected Set 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 makeString(SimpleName label) { 184 if (label == null) 185 return UNLABELED; 186 else 187 return label.getIdentifier(); 188 } 189 190 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 (2); 205 fExceptions.add(type); 206 } 207 208 protected void removeExceptions(TryStatement node) { 209 if (fExceptions == null) 210 return; 211 212 List catchClauses= node.catchClauses(); 213 if (catchClauses.isEmpty()) 214 return; 215 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 catchClauses, ITypeBinding type) { 225 for (Iterator 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 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 (); 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 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 mergeSets(Set thisSet, Set otherSet) { 288 if (otherSet != null) { 289 if (thisSet == null) { 290 thisSet= otherSet; 291 } else { 292 Iterator iter= otherSet.iterator(); 293 while (iter.hasNext()) { 294 thisSet.add(iter.next()); 295 } 296 } 297 } 298 return thisSet; 299 } 300 301 303 312 public IVariableBinding[] get(FlowContext context, int mode) { 313 List result= new ArrayList (); 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 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 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) 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) return; 375 376 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) { 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 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 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 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 |