1 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import org.eclipse.jdt.internal.compiler.ASTVisitor; 14 import org.eclipse.jdt.internal.compiler.impl.*; 15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 16 import org.eclipse.jdt.internal.compiler.codegen.*; 17 import org.eclipse.jdt.internal.compiler.flow.*; 18 import org.eclipse.jdt.internal.compiler.lookup.*; 19 20 public class ConditionalExpression extends OperatorExpression { 21 22 public Expression condition, valueIfTrue, valueIfFalse; 23 public Constant optimizedBooleanConstant; 24 public Constant optimizedIfTrueConstant; 25 public Constant optimizedIfFalseConstant; 26 27 int trueInitStateIndex = -1; 29 int falseInitStateIndex = -1; 30 int mergedInitStateIndex = -1; 31 32 public ConditionalExpression( 33 Expression condition, 34 Expression valueIfTrue, 35 Expression valueIfFalse) { 36 this.condition = condition; 37 this.valueIfTrue = valueIfTrue; 38 this.valueIfFalse = valueIfFalse; 39 sourceStart = condition.sourceStart; 40 sourceEnd = valueIfFalse.sourceEnd; 41 } 42 43 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, 44 FlowInfo flowInfo) { 45 Constant cst = this.condition.optimizedBooleanConstant(); 46 boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; 47 boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; 48 49 int mode = flowInfo.reachMode(); 50 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo, cst == Constant.NotAConstant); 51 52 FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy(); 54 if (isConditionOptimizedFalse) { 55 trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 56 } 57 trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo); 58 trueFlowInfo = valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo); 59 60 FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy(); 62 if (isConditionOptimizedTrue) { 63 falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 64 } 65 falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo); 66 falseFlowInfo = valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo); 67 68 FlowInfo mergedInfo; 70 if (isConditionOptimizedTrue){ 71 mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo); 72 } else if (isConditionOptimizedFalse) { 73 mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo); 74 } else { 75 cst = this.optimizedIfTrueConstant; 77 boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; 78 boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; 79 80 cst = this.optimizedIfFalseConstant; 81 boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; 82 boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; 83 84 UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().unconditionalCopy(); 85 UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().unconditionalCopy(); 86 UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().unconditionalInits(); 87 UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().unconditionalInits(); 88 if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); 89 if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); 90 if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); 91 if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); 92 93 mergedInfo = 94 FlowInfo.conditional( 95 trueInfoWhenTrue.mergedWith(falseInfoWhenTrue), 96 trueInfoWhenFalse.mergedWith(falseInfoWhenFalse)); 97 } 98 mergedInitStateIndex = 99 currentScope.methodScope().recordInitializationStates(mergedInfo); 100 mergedInfo.setReachMode(mode); 101 return mergedInfo; 102 } 103 104 111 public void generateCode( 112 BlockScope currentScope, 113 CodeStream codeStream, 114 boolean valueRequired) { 115 116 int pc = codeStream.position; 117 BranchLabel endifLabel, falseLabel; 118 if (constant != Constant.NotAConstant) { 119 if (valueRequired) 120 codeStream.generateConstant(constant, implicitConversion); 121 codeStream.recordPositionsFrom(pc, this.sourceStart); 122 return; 123 } 124 Constant cst = condition.optimizedBooleanConstant(); 125 boolean needTruePart = !(cst != Constant.NotAConstant && cst.booleanValue() == false); 126 boolean needFalsePart = !(cst != Constant.NotAConstant && cst.booleanValue() == true); 127 endifLabel = new BranchLabel(codeStream); 128 129 falseLabel = new BranchLabel(codeStream); 131 falseLabel.tagBits |= BranchLabel.USED; 132 condition.generateOptimizedBoolean( 133 currentScope, 134 codeStream, 135 null, 136 falseLabel, 137 cst == Constant.NotAConstant); 138 139 if (trueInitStateIndex != -1) { 140 codeStream.removeNotDefinitelyAssignedVariables( 141 currentScope, 142 trueInitStateIndex); 143 codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex); 144 } 145 if (needTruePart) { 147 valueIfTrue.generateCode(currentScope, codeStream, valueRequired); 148 if (needFalsePart) { 149 int position = codeStream.position; 151 codeStream.goto_(endifLabel); 152 codeStream.updateLastRecordedEndPC(currentScope, position); 153 if (valueRequired) { 155 codeStream.decrStackSize(this.resolvedType == TypeBinding.LONG || this.resolvedType == TypeBinding.DOUBLE ? 2 : 1); 156 } 157 } 158 } 159 if (needFalsePart) { 160 if (falseInitStateIndex != -1) { 161 codeStream.removeNotDefinitelyAssignedVariables( 162 currentScope, 163 falseInitStateIndex); 164 codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex); 165 } 166 if (falseLabel.forwardReferenceCount() > 0) { 167 falseLabel.place(); 168 } 169 valueIfFalse.generateCode(currentScope, codeStream, valueRequired); 170 if (valueRequired) { 171 codeStream.recordExpressionType(this.resolvedType); 172 } 173 if (needTruePart) { 174 endifLabel.place(); 176 } 177 } 178 if (mergedInitStateIndex != -1) { 180 codeStream.removeNotDefinitelyAssignedVariables( 181 currentScope, 182 mergedInitStateIndex); 183 } 184 if (valueRequired) 186 codeStream.generateImplicitConversion(implicitConversion); 187 codeStream.recordPositionsFrom(pc, this.sourceStart); 188 } 189 190 193 public void generateOptimizedBoolean( 194 BlockScope currentScope, 195 CodeStream codeStream, 196 BranchLabel trueLabel, 197 BranchLabel falseLabel, 198 boolean valueRequired) { 199 200 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean) || ((valueIfTrue.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_boolean) { super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); 203 return; 204 } 205 Constant cst = condition.constant; 206 Constant condCst = condition.optimizedBooleanConstant(); 207 boolean needTruePart = 208 !(((cst != Constant.NotAConstant) && (cst.booleanValue() == false)) 209 || ((condCst != Constant.NotAConstant) && (condCst.booleanValue() == false))); 210 boolean needFalsePart = 211 !(((cst != Constant.NotAConstant) && (cst.booleanValue() == true)) 212 || ((condCst != Constant.NotAConstant) && (condCst.booleanValue() == true))); 213 214 BranchLabel internalFalseLabel, endifLabel = new BranchLabel(codeStream); 215 216 boolean needConditionValue = (cst == Constant.NotAConstant) && (condCst == Constant.NotAConstant); 218 condition.generateOptimizedBoolean( 219 currentScope, 220 codeStream, 221 null, 222 internalFalseLabel = new BranchLabel(codeStream), 223 needConditionValue); 224 225 if (trueInitStateIndex != -1) { 226 codeStream.removeNotDefinitelyAssignedVariables( 227 currentScope, 228 trueInitStateIndex); 229 codeStream.addDefinitelyAssignedVariables(currentScope, trueInitStateIndex); 230 } 231 if (needTruePart) { 233 valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); 234 235 if (needFalsePart) { 236 JumpEndif: { 238 if (falseLabel == null) { 239 if (trueLabel != null) { 240 cst = this.optimizedIfTrueConstant; 242 boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; 243 if (isValueIfTrueOptimizedTrue) break JumpEndif; } 245 } else { 246 if (trueLabel == null) { 248 cst = this.optimizedIfTrueConstant; 249 boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; 250 if (isValueIfTrueOptimizedFalse) break JumpEndif; } else { 252 } 254 } 255 int position = codeStream.position; 256 codeStream.goto_(endifLabel); 257 codeStream.updateLastRecordedEndPC(currentScope, position); 258 } 259 } 262 } 263 if (needFalsePart) { 264 internalFalseLabel.place(); 265 if (falseInitStateIndex != -1) { 266 codeStream.removeNotDefinitelyAssignedVariables(currentScope, falseInitStateIndex); 267 codeStream.addDefinitelyAssignedVariables(currentScope, falseInitStateIndex); 268 } 269 valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); 270 271 endifLabel.place(); 273 } 274 if (mergedInitStateIndex != -1) { 276 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 277 } 278 codeStream.updateLastRecordedEndPC(currentScope, codeStream.position); 280 } 281 282 public int nullStatus(FlowInfo flowInfo) { 283 Constant cst = this.condition.optimizedBooleanConstant(); 284 if (cst != Constant.NotAConstant) { 285 if (cst.booleanValue()) { 286 return valueIfTrue.nullStatus(flowInfo); 287 } 288 return valueIfFalse.nullStatus(flowInfo); 289 } 290 int ifTrueNullStatus = valueIfTrue.nullStatus(flowInfo), 291 ifFalseNullStatus = valueIfFalse.nullStatus(flowInfo); 292 if (ifTrueNullStatus == ifFalseNullStatus) { 293 return ifTrueNullStatus; 294 } 295 return FlowInfo.UNKNOWN; 296 } 298 299 public Constant optimizedBooleanConstant() { 300 301 return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant; 302 } 303 304 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { 305 306 condition.printExpression(indent, output).append(" ? "); valueIfTrue.printExpression(0, output).append(" : "); return valueIfFalse.printExpression(0, output); 309 } 310 311 public TypeBinding resolveType(BlockScope scope) { 312 constant = Constant.NotAConstant; 314 LookupEnvironment env = scope.environment(); 315 boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; 316 TypeBinding conditionType = condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); 317 condition.computeConversion(scope, TypeBinding.BOOLEAN, conditionType); 318 319 if (valueIfTrue instanceof CastExpression) valueIfTrue.bits |= DisableUnnecessaryCastCheck; TypeBinding originalValueIfTrueType = valueIfTrue.resolveType(scope); 321 322 if (valueIfFalse instanceof CastExpression) valueIfFalse.bits |= DisableUnnecessaryCastCheck; TypeBinding originalValueIfFalseType = valueIfFalse.resolveType(scope); 324 325 if (conditionType == null || originalValueIfTrueType == null || originalValueIfFalseType == null) 326 return null; 327 328 TypeBinding valueIfTrueType = originalValueIfTrueType; 329 TypeBinding valueIfFalseType = originalValueIfFalseType; 330 if (use15specifics && valueIfTrueType != valueIfFalseType) { 331 if (valueIfTrueType.isBaseType()) { 332 if (valueIfFalseType.isBaseType()) { 333 if (valueIfTrueType == TypeBinding.NULL) { valueIfFalseType = env.computeBoxingType(valueIfFalseType); } else if (valueIfFalseType == TypeBinding.NULL) { valueIfTrueType = env.computeBoxingType(valueIfTrueType); } 339 } else { 340 TypeBinding unboxedIfFalseType = valueIfFalseType.isBaseType() ? valueIfFalseType : env.computeBoxingType(valueIfFalseType); 342 if (valueIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) { 343 valueIfFalseType = unboxedIfFalseType; } else if (valueIfTrueType != TypeBinding.NULL) { valueIfFalseType = env.computeBoxingType(valueIfFalseType); } 347 } 348 } else if (valueIfFalseType.isBaseType()) { 349 TypeBinding unboxedIfTrueType = valueIfTrueType.isBaseType() ? valueIfTrueType : env.computeBoxingType(valueIfTrueType); 351 if (unboxedIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) { 352 valueIfTrueType = unboxedIfTrueType; } else if (valueIfFalseType != TypeBinding.NULL) { valueIfTrueType = env.computeBoxingType(valueIfTrueType); } 356 } else { 357 TypeBinding unboxedIfTrueType = env.computeBoxingType(valueIfTrueType); 359 TypeBinding unboxedIfFalseType = env.computeBoxingType(valueIfFalseType); 360 if (unboxedIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) { 361 valueIfTrueType = unboxedIfTrueType; 362 valueIfFalseType = unboxedIfFalseType; 363 } 364 } 365 } 366 Constant condConstant, trueConstant, falseConstant; 368 if ((condConstant = condition.constant) != Constant.NotAConstant 369 && (trueConstant = valueIfTrue.constant) != Constant.NotAConstant 370 && (falseConstant = valueIfFalse.constant) != Constant.NotAConstant) { 371 constant = condConstant.booleanValue() ? trueConstant : falseConstant; 374 } 375 if (valueIfTrueType == valueIfFalseType) { valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType); 377 valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType); 378 if (valueIfTrueType == TypeBinding.BOOLEAN) { 379 this.optimizedIfTrueConstant = valueIfTrue.optimizedBooleanConstant(); 380 this.optimizedIfFalseConstant = valueIfFalse.optimizedBooleanConstant(); 381 if (this.optimizedIfTrueConstant != Constant.NotAConstant 382 && this.optimizedIfFalseConstant != Constant.NotAConstant 383 && this.optimizedIfTrueConstant.booleanValue() == this.optimizedIfFalseConstant.booleanValue()) { 384 this.optimizedBooleanConstant = optimizedIfTrueConstant; 386 } else if ((condConstant = condition.optimizedBooleanConstant()) != Constant.NotAConstant) { this.optimizedBooleanConstant = condConstant.booleanValue() 388 ? this.optimizedIfTrueConstant 389 : this.optimizedIfFalseConstant; 390 } 391 } 392 return this.resolvedType = valueIfTrueType; 393 } 394 if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) { 397 if ((valueIfTrueType == TypeBinding.BYTE && valueIfFalseType == TypeBinding.SHORT) 399 || (valueIfTrueType == TypeBinding.SHORT && valueIfFalseType == TypeBinding.BYTE)) { 400 valueIfTrue.computeConversion(scope, TypeBinding.SHORT, originalValueIfTrueType); 401 valueIfFalse.computeConversion(scope, TypeBinding.SHORT, originalValueIfFalseType); 402 return this.resolvedType = TypeBinding.SHORT; 403 } 404 if ((valueIfTrueType == TypeBinding.BYTE || valueIfTrueType == TypeBinding.SHORT || valueIfTrueType == TypeBinding.CHAR) 406 && (valueIfFalseType == TypeBinding.INT 407 && valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) { 408 valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType); 409 valueIfFalse.computeConversion(scope, valueIfTrueType, originalValueIfFalseType); 410 return this.resolvedType = valueIfTrueType; 411 } 412 if ((valueIfFalseType == TypeBinding.BYTE 413 || valueIfFalseType == TypeBinding.SHORT 414 || valueIfFalseType == TypeBinding.CHAR) 415 && (valueIfTrueType == TypeBinding.INT 416 && valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) { 417 valueIfTrue.computeConversion(scope, valueIfFalseType, originalValueIfTrueType); 418 valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType); 419 return this.resolvedType = valueIfFalseType; 420 } 421 if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int) 424 && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) { 425 valueIfTrue.computeConversion(scope, TypeBinding.INT, originalValueIfTrueType); 426 valueIfFalse.computeConversion(scope, TypeBinding.INT, originalValueIfFalseType); 427 return this.resolvedType = TypeBinding.INT; 428 } 429 if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long) 431 && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) { 432 valueIfTrue.computeConversion(scope, TypeBinding.LONG, originalValueIfTrueType); 433 valueIfFalse.computeConversion(scope, TypeBinding.LONG, originalValueIfFalseType); 434 return this.resolvedType = TypeBinding.LONG; 435 } 436 if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float) 438 && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) { 439 valueIfTrue.computeConversion(scope, TypeBinding.FLOAT, originalValueIfTrueType); 440 valueIfFalse.computeConversion(scope, TypeBinding.FLOAT, originalValueIfFalseType); 441 return this.resolvedType = TypeBinding.FLOAT; 442 } 443 valueIfTrue.computeConversion(scope, TypeBinding.DOUBLE, originalValueIfTrueType); 445 valueIfFalse.computeConversion(scope, TypeBinding.DOUBLE, originalValueIfFalseType); 446 return this.resolvedType = TypeBinding.DOUBLE; 447 } 448 if (valueIfTrueType.isBaseType() && valueIfTrueType != TypeBinding.NULL) { 450 if (use15specifics) { 451 valueIfTrueType = env.computeBoxingType(valueIfTrueType); 452 } else { 453 scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType); 454 return null; 455 } 456 } 457 if (valueIfFalseType.isBaseType() && valueIfFalseType != TypeBinding.NULL) { 458 if (use15specifics) { 459 valueIfFalseType = env.computeBoxingType(valueIfFalseType); 460 } else { 461 scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType); 462 return null; 463 } 464 } 465 if (use15specifics) { 466 TypeBinding commonType = null; 468 if (valueIfTrueType == TypeBinding.NULL) { 469 commonType = valueIfFalseType; 470 } else if (valueIfFalseType == TypeBinding.NULL) { 471 commonType = valueIfTrueType; 472 } else { 473 commonType = scope.lowerUpperBound(new TypeBinding[] { valueIfTrueType, valueIfFalseType }); 474 } 475 if (commonType != null) { 476 valueIfTrue.computeConversion(scope, commonType, originalValueIfTrueType); 477 valueIfFalse.computeConversion(scope, commonType, originalValueIfFalseType); 478 return this.resolvedType = commonType.capture(scope, this.sourceEnd); 479 } 480 } else { 481 if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) { 483 valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType); 484 valueIfFalse.computeConversion(scope, valueIfTrueType, originalValueIfFalseType); 485 return this.resolvedType = valueIfTrueType; 486 } else if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) { 487 valueIfTrue.computeConversion(scope, valueIfFalseType, originalValueIfTrueType); 488 valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType); 489 return this.resolvedType = valueIfFalseType; 490 } 491 } 492 scope.problemReporter().conditionalArgumentsIncompatibleTypes( 493 this, 494 valueIfTrueType, 495 valueIfFalseType); 496 return null; 497 } 498 499 public void traverse(ASTVisitor visitor, BlockScope scope) { 500 if (visitor.visit(this, scope)) { 501 condition.traverse(visitor, scope); 502 valueIfTrue.traverse(visitor, scope); 503 valueIfFalse.traverse(visitor, scope); 504 } 505 visitor.endVisit(this, scope); 506 } 507 } 508 | Popular Tags |