1 11 package org.eclipse.jdt.internal.compiler.flow; 12 13 import org.eclipse.jdt.internal.compiler.ast.ASTNode; 14 import org.eclipse.jdt.internal.compiler.ast.Expression; 15 import org.eclipse.jdt.internal.compiler.ast.Reference; 16 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; 17 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 18 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; 19 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; 20 import org.eclipse.jdt.internal.compiler.lookup.Scope; 21 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; 22 23 27 public class LoopingFlowContext extends SwitchFlowContext { 28 29 public BranchLabel continueLabel; 30 public UnconditionalFlowInfo initsOnContinue = FlowInfo.DEAD_END; 31 private UnconditionalFlowInfo upstreamNullFlowInfo; 32 private LoopingFlowContext innerFlowContexts[] = null; 33 private UnconditionalFlowInfo innerFlowInfos[] = null; 34 private int innerFlowContextsCount = 0; 35 private LabelFlowContext breakTargetContexts[] = null; 36 private int breakTargetsCount = 0; 37 38 Reference finalAssignments[]; 39 VariableBinding finalVariables[]; 40 int assignCount = 0; 41 42 LocalVariableBinding[] nullLocals; 43 Expression[] nullReferences; 44 int[] nullCheckTypes; 45 int nullCount; 46 47 Scope associatedScope; 48 49 public LoopingFlowContext( 50 FlowContext parent, 51 FlowInfo upstreamNullFlowInfo, 52 ASTNode associatedNode, 53 BranchLabel breakLabel, 54 BranchLabel continueLabel, 55 Scope associatedScope) { 56 super(parent, associatedNode, breakLabel); 57 preemptNullDiagnostic = true; 58 this.continueLabel = continueLabel; 60 this.associatedScope = associatedScope; 61 this.upstreamNullFlowInfo = upstreamNullFlowInfo.unconditionalCopy(); 62 } 63 64 70 public void complainOnDeferredFinalChecks(BlockScope scope, FlowInfo flowInfo) { 71 for (int i = 0; i < assignCount; i++) { 73 VariableBinding variable = finalVariables[i]; 74 if (variable == null) continue; 75 boolean complained = false; if (variable instanceof FieldBinding) { 77 if (flowInfo.isPotentiallyAssigned((FieldBinding) variable)) { 78 complained = true; 79 scope.problemReporter().duplicateInitializationOfBlankFinalField( 80 (FieldBinding) variable, 81 finalAssignments[i]); 82 } 83 } else { 84 if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) { 85 complained = true; 86 scope.problemReporter().duplicateInitializationOfFinalLocal( 87 (LocalVariableBinding) variable, 88 finalAssignments[i]); 89 } 90 } 91 if (complained) { 94 FlowContext context = parent; 95 while (context != null) { 96 context.removeFinalAssignmentIfAny(finalAssignments[i]); 97 context = context.parent; 98 } 99 } 100 } 101 } 102 103 108 public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowInfo) { 109 for (int i = 0 ; i < this.innerFlowContextsCount ; i++) { 110 this.upstreamNullFlowInfo. 111 addPotentialNullInfoFrom( 112 this.innerFlowContexts[i].upstreamNullFlowInfo). 113 addPotentialNullInfoFrom(this.innerFlowInfos[i]); 114 } 115 this.innerFlowContextsCount = 0; 116 UnconditionalFlowInfo flowInfo = this.upstreamNullFlowInfo. 117 addPotentialNullInfoFrom(callerFlowInfo.unconditionalInitsWithoutSideEffect()); 118 if (this.deferNullDiagnostic) { 119 for (int i = 0; i < this.nullCount; i++) { 121 LocalVariableBinding local = this.nullLocals[i]; 122 Expression expression = this.nullReferences[i]; 123 switch (this.nullCheckTypes[i]) { 125 case CAN_ONLY_NON_NULL | IN_COMPARISON_NULL: 126 case CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL: 127 if (flowInfo.isDefinitelyNonNull(local)) { 128 this.nullReferences[i] = null; 129 if (this.nullCheckTypes[i] == (CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL)) { 130 scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression); 131 } else { 132 scope.problemReporter().localVariableNonNullComparedToNull(local, expression); 133 } 134 continue; 135 } 136 break; 137 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: 138 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: 139 if (flowInfo.isDefinitelyNonNull(local)) { 140 this.nullReferences[i] = null; 141 if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { 142 scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression); 143 } else { 144 scope.problemReporter().localVariableNonNullComparedToNull(local, expression); 145 } 146 continue; 147 } 148 if (flowInfo.isDefinitelyNull(local)) { 149 this.nullReferences[i] = null; 150 if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) { 151 scope.problemReporter().localVariableRedundantCheckOnNull(local, expression); 152 } else { 153 scope.problemReporter().localVariableNullComparedToNonNull(local, expression); 154 } 155 continue; 156 } 157 break; 158 case CAN_ONLY_NULL | IN_COMPARISON_NULL: 159 case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: 160 case CAN_ONLY_NULL | IN_ASSIGNMENT: 161 case CAN_ONLY_NULL | IN_INSTANCEOF: 162 if (flowInfo.isDefinitelyNull(local)) { 163 this.nullReferences[i] = null; 164 switch(this.nullCheckTypes[i] & CONTEXT_MASK) { 165 case FlowContext.IN_COMPARISON_NULL: 166 scope.problemReporter().localVariableRedundantCheckOnNull(local, expression); 167 continue; 168 case FlowContext.IN_COMPARISON_NON_NULL: 169 scope.problemReporter().localVariableNullComparedToNonNull(local, expression); 170 continue; 171 case FlowContext.IN_ASSIGNMENT: 172 scope.problemReporter().localVariableRedundantNullAssignment(local, expression); 173 continue; 174 case FlowContext.IN_INSTANCEOF: 175 scope.problemReporter().localVariableNullInstanceof(local, expression); 176 continue; 177 } 178 } 179 break; 180 case MAY_NULL: 181 if (flowInfo.isDefinitelyNull(local)) { 182 this.nullReferences[i] = null; 183 scope.problemReporter().localVariableNullReference(local, expression); 184 continue; 185 } 186 break; 187 default: 188 } 190 this.parent.recordUsingNullReference(scope, local, expression, 191 this.nullCheckTypes[i], flowInfo); 192 } 193 } 194 else { 195 for (int i = 0; i < this.nullCount; i++) { 197 Expression expression = this.nullReferences[i]; 198 LocalVariableBinding local = this.nullLocals[i]; 200 switch (this.nullCheckTypes[i]) { 201 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: 202 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: 203 if (flowInfo.isDefinitelyNonNull(local)) { 204 this.nullReferences[i] = null; 205 if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { 206 scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression); 207 } else { 208 scope.problemReporter().localVariableNonNullComparedToNull(local, expression); 209 } 210 continue; 211 } 212 case CAN_ONLY_NULL | IN_COMPARISON_NULL: 213 case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: 214 case CAN_ONLY_NULL | IN_ASSIGNMENT: 215 case CAN_ONLY_NULL | IN_INSTANCEOF: 216 if (flowInfo.isDefinitelyNull(local)) { 217 this.nullReferences[i] = null; 218 switch(this.nullCheckTypes[i] & CONTEXT_MASK) { 219 case FlowContext.IN_COMPARISON_NULL: 220 scope.problemReporter().localVariableRedundantCheckOnNull(local, expression); 221 continue; 222 case FlowContext.IN_COMPARISON_NON_NULL: 223 scope.problemReporter().localVariableNullComparedToNonNull(local, expression); 224 continue; 225 case FlowContext.IN_ASSIGNMENT: 226 scope.problemReporter().localVariableRedundantNullAssignment(local, expression); 227 continue; 228 case FlowContext.IN_INSTANCEOF: 229 scope.problemReporter().localVariableNullInstanceof(local, expression); 230 continue; 231 } 232 } 233 break; 234 case MAY_NULL: 235 if (flowInfo.isDefinitelyNull(local)) { 236 this.nullReferences[i] = null; 237 scope.problemReporter().localVariableNullReference(local, expression); 238 continue; 239 } 240 if (flowInfo.isPotentiallyNull(local)) { 241 this.nullReferences[i] = null; 242 scope.problemReporter().localVariablePotentialNullReference(local, expression); 243 continue; 244 } 245 break; 246 default: 247 } 249 } 250 } 251 for (int i = 0; i < this.breakTargetsCount; i++) { 253 this.breakTargetContexts[i].initsOnBreak.addPotentialNullInfoFrom(flowInfo); 254 } 255 } 256 257 public BranchLabel continueLabel() { 258 return continueLabel; 259 } 260 261 public String individualToString() { 262 StringBuffer buffer = new StringBuffer ("Looping flow context"); buffer.append("[initsOnBreak - ").append(initsOnBreak.toString()).append(']'); buffer.append("[initsOnContinue - ").append(initsOnContinue.toString()).append(']'); buffer.append("[finalAssignments count - ").append(assignCount).append(']'); buffer.append("[nullReferences count - ").append(nullCount).append(']'); return buffer.toString(); 268 } 269 270 public boolean isContinuable() { 271 return true; 272 } 273 274 public boolean isContinuedTo() { 275 return initsOnContinue != FlowInfo.DEAD_END; 276 } 277 278 public void recordBreakTo(FlowContext targetContext) { 279 if (targetContext instanceof LabelFlowContext) { 280 int current; 281 if ((current = this.breakTargetsCount++) == 0) { 282 this.breakTargetContexts = new LabelFlowContext[2]; 283 } else if (current == this.breakTargetContexts.length) { 284 System.arraycopy(this.breakTargetContexts, 0, this.breakTargetContexts = new LabelFlowContext[current + 2], 0, current); 285 } 286 this.breakTargetContexts[current] = (LabelFlowContext) targetContext; 287 } 288 } 289 290 public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) { 291 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { 292 if ((initsOnContinue.tagBits & FlowInfo.UNREACHABLE) == 0) { 293 initsOnContinue = initsOnContinue. 294 mergedWith(flowInfo.unconditionalInitsWithoutSideEffect()); 295 } 296 else { 297 initsOnContinue = flowInfo.unconditionalCopy(); 298 } 299 FlowContext inner = innerFlowContext; 300 while (inner != this && !(inner instanceof LoopingFlowContext)) { 301 inner = inner.parent; 302 } 303 if (inner == this) { 304 this.upstreamNullFlowInfo. 305 addPotentialNullInfoFrom( 306 flowInfo.unconditionalInitsWithoutSideEffect()); 307 } 308 else { 309 int length = 0; 310 if (this.innerFlowContexts == null) { 311 this.innerFlowContexts = new LoopingFlowContext[5]; 312 this.innerFlowInfos = new UnconditionalFlowInfo[5]; 313 } 314 else if (this.innerFlowContextsCount == 315 (length = this.innerFlowContexts.length) - 1) { 316 System.arraycopy(this.innerFlowContexts, 0, 317 (this.innerFlowContexts = new LoopingFlowContext[length + 5]), 318 0, length); 319 System.arraycopy(this.innerFlowInfos, 0, 320 (this.innerFlowInfos= new UnconditionalFlowInfo[length + 5]), 321 0, length); 322 } 323 this.innerFlowContexts[this.innerFlowContextsCount] = (LoopingFlowContext) inner; 324 this.innerFlowInfos[this.innerFlowContextsCount++] = 325 flowInfo.unconditionalInitsWithoutSideEffect(); 326 } 327 } 328 } 329 330 protected boolean recordFinalAssignment( 331 VariableBinding binding, 332 Reference finalAssignment) { 333 334 if (binding instanceof LocalVariableBinding) { 336 Scope scope = ((LocalVariableBinding) binding).declaringScope; 337 while ((scope = scope.parent) != null) { 338 if (scope == associatedScope) 339 return false; 340 } 341 } 342 if (assignCount == 0) { 343 finalAssignments = new Reference[5]; 344 finalVariables = new VariableBinding[5]; 345 } else { 346 if (assignCount == finalAssignments.length) 347 System.arraycopy( 348 finalAssignments, 349 0, 350 (finalAssignments = new Reference[assignCount * 2]), 351 0, 352 assignCount); 353 System.arraycopy( 354 finalVariables, 355 0, 356 (finalVariables = new VariableBinding[assignCount * 2]), 357 0, 358 assignCount); 359 } 360 finalAssignments[assignCount] = finalAssignment; 361 finalVariables[assignCount++] = binding; 362 return true; 363 } 364 365 protected void recordNullReference(LocalVariableBinding local, 366 Expression expression, int status) { 367 if (nullCount == 0) { 368 nullLocals = new LocalVariableBinding[5]; 369 nullReferences = new Expression[5]; 370 nullCheckTypes = new int[5]; 371 } 372 else if (nullCount == nullLocals.length) { 373 System.arraycopy(nullLocals, 0, 374 nullLocals = new LocalVariableBinding[nullCount * 2], 0, nullCount); 375 System.arraycopy(nullReferences, 0, 376 nullReferences = new Expression[nullCount * 2], 0, nullCount); 377 System.arraycopy(nullCheckTypes, 0, 378 nullCheckTypes = new int[nullCount * 2], 0, nullCount); 379 } 380 nullLocals[nullCount] = local; 381 nullReferences[nullCount] = expression; 382 nullCheckTypes[nullCount++] = status; 383 } 384 385 public void recordUsingNullReference(Scope scope, LocalVariableBinding local, 386 Expression reference, int checkType, FlowInfo flowInfo) { 387 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 || 388 flowInfo.isDefinitelyUnknown(local)) { 389 return; 390 } 391 switch (checkType) { 392 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL: 393 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL: 394 if (flowInfo.isDefinitelyNonNull(local)) { 395 if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) { 396 scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference); 397 } else { 398 scope.problemReporter().localVariableNonNullComparedToNull(local, reference); 399 } 400 } else if (flowInfo.isDefinitelyNull(local)) { 401 if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) { 402 scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); 403 } else { 404 scope.problemReporter().localVariableNullComparedToNonNull(local, reference); 405 } 406 } else if (! flowInfo.cannotBeDefinitelyNullOrNonNull(local)) { 407 if (flowInfo.isPotentiallyNonNull(local)) { 408 recordNullReference(local, reference, CAN_ONLY_NON_NULL | checkType & CONTEXT_MASK); 409 } else { 410 recordNullReference(local, reference, checkType); 411 } 412 } 413 return; 414 case CAN_ONLY_NULL | IN_COMPARISON_NULL: 415 case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL: 416 case CAN_ONLY_NULL | IN_ASSIGNMENT: 417 case CAN_ONLY_NULL | IN_INSTANCEOF: 418 if (flowInfo.isPotentiallyNonNull(local) 419 || flowInfo.isPotentiallyUnknown(local)) { 420 return; 421 } 422 if (flowInfo.isDefinitelyNull(local)) { 423 switch(checkType & CONTEXT_MASK) { 424 case FlowContext.IN_COMPARISON_NULL: 425 scope.problemReporter().localVariableRedundantCheckOnNull(local, reference); 426 return; 427 case FlowContext.IN_COMPARISON_NON_NULL: 428 scope.problemReporter().localVariableNullComparedToNonNull(local, reference); 429 return; 430 case FlowContext.IN_ASSIGNMENT: 431 scope.problemReporter().localVariableRedundantNullAssignment(local, reference); 432 return; 433 case FlowContext.IN_INSTANCEOF: 434 scope.problemReporter().localVariableNullInstanceof(local, reference); 435 return; 436 } 437 } 438 recordNullReference(local, reference, checkType); 439 return; 440 case MAY_NULL : 441 if (flowInfo.isDefinitelyNonNull(local)) { 442 return; 443 } 444 if (flowInfo.isDefinitelyNull(local)) { 445 scope.problemReporter().localVariableNullReference(local, reference); 446 return; 447 } 448 if (flowInfo.isPotentiallyNull(local)) { 449 scope.problemReporter().localVariablePotentialNullReference(local, reference); 450 return; 451 } 452 recordNullReference(local, reference, checkType); 453 return; 454 default: 455 } 457 } 458 459 void removeFinalAssignmentIfAny(Reference reference) { 460 for (int i = 0; i < assignCount; i++) { 461 if (finalAssignments[i] == reference) { 462 finalAssignments[i] = null; 463 finalVariables[i] = null; 464 return; 465 } 466 } 467 } 468 } 469 | Popular Tags |