1 11 package org.eclipse.jdt.internal.compiler.flow; 12 13 import org.eclipse.jdt.core.compiler.CharOperation; 14 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; 15 import org.eclipse.jdt.internal.compiler.ast.ASTNode; 16 import org.eclipse.jdt.internal.compiler.ast.Expression; 17 import org.eclipse.jdt.internal.compiler.ast.LabeledStatement; 18 import org.eclipse.jdt.internal.compiler.ast.Reference; 19 import org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement; 20 import org.eclipse.jdt.internal.compiler.ast.TryStatement; 21 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; 22 import org.eclipse.jdt.internal.compiler.lookup.Binding; 23 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 24 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; 25 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 26 import org.eclipse.jdt.internal.compiler.lookup.Scope; 27 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; 28 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; 29 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; 30 31 35 public class FlowContext implements TypeConstants { 36 37 public final static FlowContext NotContinuableContext = new FlowContext(null, null); 39 public ASTNode associatedNode; 40 public FlowContext parent; 41 public NullInfoRegistry initsOnFinally; 42 45 boolean deferNullDiagnostic, preemptNullDiagnostic; 46 47 public FlowContext(FlowContext parent, ASTNode associatedNode) { 48 this.parent = parent; 49 this.associatedNode = associatedNode; 50 if (parent != null) { 51 this.deferNullDiagnostic = 52 parent.deferNullDiagnostic || parent.preemptNullDiagnostic; 53 this.initsOnFinally = parent.initsOnFinally; 54 } 55 } 56 57 public BranchLabel breakLabel() { 58 return null; 59 } 60 61 public void checkExceptionHandlers(TypeBinding raisedException, ASTNode location, FlowInfo flowInfo, BlockScope scope) { 62 FlowContext traversedContext = this; 68 while (traversedContext != null) { 69 SubRoutineStatement sub; 70 if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) { 71 return; 74 } 75 76 if (traversedContext instanceof ExceptionHandlingFlowContext) { 79 ExceptionHandlingFlowContext exceptionContext = 80 (ExceptionHandlingFlowContext) traversedContext; 81 ReferenceBinding[] caughtExceptions; 82 if ((caughtExceptions = exceptionContext.handledExceptions) != Binding.NO_EXCEPTIONS) { 83 boolean definitelyCaught = false; 84 for (int caughtIndex = 0, caughtCount = caughtExceptions.length; 85 caughtIndex < caughtCount; 86 caughtIndex++) { 87 ReferenceBinding caughtException = caughtExceptions[caughtIndex]; 88 int state = caughtException == null 89 ? Scope.EQUAL_OR_MORE_SPECIFIC 90 : Scope.compareTypes(raisedException, caughtException); 91 switch (state) { 92 case Scope.EQUAL_OR_MORE_SPECIFIC : 93 exceptionContext.recordHandlingException( 94 caughtException, 95 flowInfo.unconditionalInits(), 96 raisedException, 97 location, 98 definitelyCaught); 99 definitelyCaught = true; 101 break; 102 case Scope.MORE_GENERIC : 103 exceptionContext.recordHandlingException( 104 caughtException, 105 flowInfo.unconditionalInits(), 106 raisedException, 107 location, 108 false); 109 } 111 } 112 if (definitelyCaught) 113 return; 114 } 115 if (exceptionContext.isMethodContext) { 117 if (raisedException.isUncheckedException(false)) 118 return; 119 120 if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){ 123 AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode; 124 if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){ 125 126 exceptionContext.mergeUnhandledException(raisedException); 127 return; } 129 } 130 break; } 132 } 133 134 traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); 135 136 if (traversedContext instanceof InsideSubRoutineFlowContext) { 137 ASTNode node = traversedContext.associatedNode; 138 if (node instanceof TryStatement) { 139 TryStatement tryStatement = (TryStatement) node; 140 flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); } 142 } 143 traversedContext = traversedContext.parent; 144 } 145 scope.problemReporter().unhandledException(raisedException, location); 147 } 148 149 public void checkExceptionHandlers(TypeBinding[] raisedExceptions, ASTNode location, FlowInfo flowInfo, BlockScope scope) { 150 int remainingCount; int raisedCount; if ((raisedExceptions == null) 157 || ((raisedCount = raisedExceptions.length) == 0)) 158 return; 159 remainingCount = raisedCount; 160 161 System.arraycopy( 164 raisedExceptions, 165 0, 166 (raisedExceptions = new TypeBinding[raisedCount]), 167 0, 168 raisedCount); 169 FlowContext traversedContext = this; 170 171 while (traversedContext != null) { 172 SubRoutineStatement sub; 173 if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) { 174 return; 177 } 178 if (traversedContext instanceof ExceptionHandlingFlowContext) { 181 ExceptionHandlingFlowContext exceptionContext = 182 (ExceptionHandlingFlowContext) traversedContext; 183 ReferenceBinding[] caughtExceptions; 184 if ((caughtExceptions = exceptionContext.handledExceptions) != Binding.NO_EXCEPTIONS) { 185 int caughtCount = caughtExceptions.length; 186 boolean[] locallyCaught = new boolean[raisedCount]; 188 for (int caughtIndex = 0; caughtIndex < caughtCount; caughtIndex++) { 189 ReferenceBinding caughtException = caughtExceptions[caughtIndex]; 190 for (int raisedIndex = 0; raisedIndex < raisedCount; raisedIndex++) { 191 TypeBinding raisedException; 192 if ((raisedException = raisedExceptions[raisedIndex]) != null) { 193 int state = caughtException == null 194 ? Scope.EQUAL_OR_MORE_SPECIFIC 195 : Scope.compareTypes(raisedException, caughtException); 196 switch (state) { 197 case Scope.EQUAL_OR_MORE_SPECIFIC : 198 exceptionContext.recordHandlingException( 199 caughtException, 200 flowInfo.unconditionalInits(), 201 raisedException, 202 location, 203 locallyCaught[raisedIndex]); 204 if (!locallyCaught[raisedIndex]) { 206 locallyCaught[raisedIndex] = true; 207 remainingCount--; 209 } 210 break; 211 case Scope.MORE_GENERIC : 212 exceptionContext.recordHandlingException( 213 caughtException, 214 flowInfo.unconditionalInits(), 215 raisedException, 216 location, 217 false); 218 } 220 } 221 } 222 } 223 for (int i = 0; i < raisedCount; i++) { 225 if (locallyCaught[i]) { 226 raisedExceptions[i] = null; } 228 } 229 } 230 if (exceptionContext.isMethodContext) { 232 for (int i = 0; i < raisedCount; i++) { 233 TypeBinding raisedException; 234 if ((raisedException = raisedExceptions[i]) != null) { 235 if (raisedException.isUncheckedException(false)) { 236 remainingCount--; 237 raisedExceptions[i] = null; 238 } 239 } 240 } 241 if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration){ 244 AbstractMethodDeclaration method = (AbstractMethodDeclaration)exceptionContext.associatedNode; 245 if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()){ 246 247 for (int i = 0; i < raisedCount; i++) { 248 TypeBinding raisedException; 249 if ((raisedException = raisedExceptions[i]) != null) { 250 exceptionContext.mergeUnhandledException(raisedException); 251 } 252 } 253 return; } 255 } 256 break; } 258 } 259 if (remainingCount == 0) 260 return; 261 262 traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); 263 264 if (traversedContext instanceof InsideSubRoutineFlowContext) { 265 ASTNode node = traversedContext.associatedNode; 266 if (node instanceof TryStatement) { 267 TryStatement tryStatement = (TryStatement) node; 268 flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); } 270 } 271 traversedContext = traversedContext.parent; 272 } 273 nextReport: for (int i = 0; i < raisedCount; i++) { 275 TypeBinding exception; 276 if ((exception = raisedExceptions[i]) != null) { 277 for (int j = 0; j < i; j++) { 279 if (raisedExceptions[j] == exception) continue nextReport; } 281 scope.problemReporter().unhandledException(exception, location); 282 } 283 } 284 } 285 286 public BranchLabel continueLabel() { 287 return null; 288 } 289 290 293 public FlowContext getTargetContextForBreakLabel(char[] labelName) { 294 FlowContext current = this, lastNonReturningSubRoutine = null; 295 while (current != null) { 296 if (current.isNonReturningContext()) { 297 lastNonReturningSubRoutine = current; 298 } 299 char[] currentLabelName; 300 if (((currentLabelName = current.labelName()) != null) 301 && CharOperation.equals(currentLabelName, labelName)) { 302 ((LabeledStatement)current.associatedNode).bits |= ASTNode.LabelUsed; 303 if (lastNonReturningSubRoutine == null) 304 return current; 305 return lastNonReturningSubRoutine; 306 } 307 current = current.parent; 308 } 309 return null; 311 } 312 313 316 public FlowContext getTargetContextForContinueLabel(char[] labelName) { 317 FlowContext current = this; 318 FlowContext lastContinuable = null; 319 FlowContext lastNonReturningSubRoutine = null; 320 321 while (current != null) { 322 if (current.isNonReturningContext()) { 323 lastNonReturningSubRoutine = current; 324 } else { 325 if (current.isContinuable()) { 326 lastContinuable = current; 327 } 328 } 329 330 char[] currentLabelName; 331 if ((currentLabelName = current.labelName()) != null && CharOperation.equals(currentLabelName, labelName)) { 332 ((LabeledStatement)current.associatedNode).bits |= ASTNode.LabelUsed; 333 334 if ((lastContinuable != null) 336 && (current.associatedNode.concreteStatement() == lastContinuable.associatedNode)) { 337 338 if (lastNonReturningSubRoutine == null) return lastContinuable; 339 return lastNonReturningSubRoutine; 340 } 341 return FlowContext.NotContinuableContext; 343 } 344 current = current.parent; 345 } 346 return null; 348 } 349 350 353 public FlowContext getTargetContextForDefaultBreak() { 354 FlowContext current = this, lastNonReturningSubRoutine = null; 355 while (current != null) { 356 if (current.isNonReturningContext()) { 357 lastNonReturningSubRoutine = current; 358 } 359 if (current.isBreakable() && current.labelName() == null) { 360 if (lastNonReturningSubRoutine == null) return current; 361 return lastNonReturningSubRoutine; 362 } 363 current = current.parent; 364 } 365 return null; 367 } 368 369 372 public FlowContext getTargetContextForDefaultContinue() { 373 FlowContext current = this, lastNonReturningSubRoutine = null; 374 while (current != null) { 375 if (current.isNonReturningContext()) { 376 lastNonReturningSubRoutine = current; 377 } 378 if (current.isContinuable()) { 379 if (lastNonReturningSubRoutine == null) 380 return current; 381 return lastNonReturningSubRoutine; 382 } 383 current = current.parent; 384 } 385 return null; 387 } 388 389 public String individualToString() { 390 return "Flow context"; } 392 393 public FlowInfo initsOnBreak() { 394 return FlowInfo.DEAD_END; 395 } 396 397 public UnconditionalFlowInfo initsOnReturn() { 398 return FlowInfo.DEAD_END; 399 } 400 401 public boolean isBreakable() { 402 return false; 403 } 404 405 public boolean isContinuable() { 406 return false; 407 } 408 409 public boolean isNonReturningContext() { 410 return false; 411 } 412 413 public boolean isSubRoutine() { 414 return false; 415 } 416 417 public char[] labelName() { 418 return null; 419 } 420 421 public void recordBreakFrom(FlowInfo flowInfo) { 422 } 424 425 public void recordBreakTo(FlowContext targetContext) { 426 } 428 429 public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) { 430 } 432 433 protected boolean recordFinalAssignment(VariableBinding variable, Reference finalReference) { 434 return true; } 436 437 449 protected void recordNullReference(LocalVariableBinding local, 450 Expression expression, int status) { 451 } 453 454 public void recordReturnFrom(UnconditionalFlowInfo flowInfo) { 455 } 457 458 public void recordSettingFinal(VariableBinding variable, Reference finalReference, FlowInfo flowInfo) { 459 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { 460 FlowContext context = this; 462 while (context != null) { 463 if (!context.recordFinalAssignment(variable, finalReference)) { 464 break; } 466 context = context.parent; 467 } 468 } 469 } 470 471 public static final int 472 CAN_ONLY_NULL_NON_NULL = 0x0000, 473 CAN_ONLY_NULL = 0x0001, 475 CAN_ONLY_NON_NULL = 0x0002, 477 MAY_NULL = 0x0003, 479 CHECK_MASK = 0x00FF, 481 IN_COMPARISON_NULL = 0x0100, 482 IN_COMPARISON_NON_NULL = 0x0200, 483 IN_ASSIGNMENT = 0x0300, 485 IN_INSTANCEOF = 0x0400, 487 CONTEXT_MASK = ~CHECK_MASK; 489 490 511 public void recordUsingNullReference(Scope scope, LocalVariableBinding local, 512 Expression reference, int checkType, FlowInfo flowInfo) { 513 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 || 514 flowInfo.isDefinitelyUnknown(local)) { 515 return; 516 } 517 switch (checkType) { 518 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: 519 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: 520 if (flowInfo.isDefinitelyNonNull(local)) { 521 if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { 522 scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference); 523 } else { 524 scope.problemReporter().localVariableNonNullComparedToNull(local, reference); 525 } 526 return; 527 } 528 else if (flowInfo.cannotBeDefinitelyNullOrNonNull(local)) { 529 return; 530 } 531 case CAN_ONLY_NULL | IN_COMPARISON_NULL: 532 case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: 533 case CAN_ONLY_NULL | IN_ASSIGNMENT: 534 case CAN_ONLY_NULL | IN_INSTANCEOF: 535 if (flowInfo.isDefinitelyNull(local)) { 536 switch(checkType & CONTEXT_MASK) { 537 case FlowContext.IN_COMPARISON_NULL: 538 scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); 539 return; 540 case FlowContext.IN_COMPARISON_NON_NULL: 541 scope.problemReporter().localVariableNullComparedToNonNull(local, reference); 542 return; 543 case FlowContext.IN_ASSIGNMENT: 544 scope.problemReporter().localVariableRedundantNullAssignment(local, reference); 545 return; 546 case FlowContext.IN_INSTANCEOF: 547 scope.problemReporter().localVariableNullInstanceof(local, reference); 548 return; 549 } 550 } else if (flowInfo.cannotBeDefinitelyNullOrNonNull(local)) { 551 return; 552 } 553 break; 554 case MAY_NULL : 555 if (flowInfo.isDefinitelyNull(local)) { 556 scope.problemReporter().localVariableNullReference(local, reference); 557 return; 558 } 559 if (flowInfo.isPotentiallyNull(local)) { 560 scope.problemReporter().localVariablePotentialNullReference(local, reference); 561 return; 562 } 563 break; 564 default: 565 } 567 if (this.parent != null) { 568 this.parent.recordUsingNullReference(scope, local, reference, checkType, 569 flowInfo); 570 } 571 } 572 573 void removeFinalAssignmentIfAny(Reference reference) { 574 } 576 577 public SubRoutineStatement subroutine() { 578 return null; 579 } 580 581 public String toString() { 582 StringBuffer buffer = new StringBuffer (); 583 FlowContext current = this; 584 int parentsCount = 0; 585 while ((current = current.parent) != null) { 586 parentsCount++; 587 } 588 FlowContext[] parents = new FlowContext[parentsCount + 1]; 589 current = this; 590 int index = parentsCount; 591 while (index >= 0) { 592 parents[index--] = current; 593 current = current.parent; 594 } 595 for (int i = 0; i < parentsCount; i++) { 596 for (int j = 0; j < i; j++) 597 buffer.append('\t'); 598 buffer.append(parents[i].individualToString()).append('\n'); 599 } 600 buffer.append('*'); 601 for (int j = 0; j < parentsCount + 1; j++) 602 buffer.append('\t'); 603 buffer.append(individualToString()).append('\n'); 604 return buffer.toString(); 605 } 606 } 607 | Popular Tags |