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.classfmt.ClassFileConstants; 15 import org.eclipse.jdt.internal.compiler.codegen.*; 16 import org.eclipse.jdt.internal.compiler.flow.*; 17 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; 18 import org.eclipse.jdt.internal.compiler.impl.Constant; 19 import org.eclipse.jdt.internal.compiler.lookup.*; 20 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; 21 22 public class SwitchStatement extends Statement { 23 24 public Expression expression; 25 public Statement[] statements; 26 public BlockScope scope; 27 public int explicitDeclarations; 28 public BranchLabel breakLabel; 29 public CaseStatement[] cases; 30 public CaseStatement defaultCase; 31 public int blockStart; 32 public int caseCount; 33 int[] constants; 34 35 public final static int CASE = 0; 37 public final static int FALLTHROUGH = 1; 38 public final static int ESCAPING = 2; 39 40 41 public SyntheticMethodBinding synthetic; 43 int preSwitchInitStateIndex = -1; 45 int mergedInitStateIndex = -1; 46 47 public FlowInfo analyseCode( 48 BlockScope currentScope, 49 FlowContext flowContext, 50 FlowInfo flowInfo) { 51 52 try { 53 flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo); 54 SwitchFlowContext switchContext = 55 new SwitchFlowContext(flowContext, this, (breakLabel = new BranchLabel())); 56 57 FlowInfo caseInits = FlowInfo.DEAD_END; 60 preSwitchInitStateIndex = 62 currentScope.methodScope().recordInitializationStates(flowInfo); 63 int caseIndex = 0; 64 if (statements != null) { 65 boolean didAlreadyComplain = false; 66 int fallThroughState = CASE; 67 for (int i = 0, max = statements.length; i < max; i++) { 68 Statement statement = statements[i]; 69 if ((caseIndex < caseCount) && (statement == cases[caseIndex])) { this.scope.enclosingCase = cases[caseIndex]; caseIndex++; 72 if (fallThroughState == FALLTHROUGH 73 && (statement.bits & ASTNode.DocumentedFallthrough) == 0) { scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase); 75 } 76 caseInits = caseInits.mergedWith(flowInfo.unconditionalInits()); 77 didAlreadyComplain = false; fallThroughState = CASE; 79 } else if (statement == defaultCase) { this.scope.enclosingCase = defaultCase; if (fallThroughState == FALLTHROUGH 82 && (statement.bits & ASTNode.DocumentedFallthrough) == 0) { 83 scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase); 84 } 85 caseInits = caseInits.mergedWith(flowInfo.unconditionalInits()); 86 didAlreadyComplain = false; fallThroughState = CASE; 88 } else { 89 fallThroughState = FALLTHROUGH; } 91 if (!statement.complainIfUnreachable(caseInits, scope, didAlreadyComplain)) { 92 caseInits = statement.analyseCode(scope, switchContext, caseInits); 93 if (caseInits == FlowInfo.DEAD_END) { 94 fallThroughState = ESCAPING; 95 } 96 } else { 97 didAlreadyComplain = true; 98 } 99 } 100 } 101 102 final TypeBinding resolvedTypeBinding = this.expression.resolvedType; 103 if (caseCount > 0 && resolvedTypeBinding.isEnum()) { 104 final SourceTypeBinding sourceTypeBinding = this.scope.classScope().referenceContext.binding; 105 this.synthetic = sourceTypeBinding.addSyntheticMethodForSwitchEnum(resolvedTypeBinding); 106 } 107 if (defaultCase == null) { 109 flowInfo.addPotentialInitializationsFrom( 111 caseInits.mergedWith(switchContext.initsOnBreak)); 112 mergedInitStateIndex = 113 currentScope.methodScope().recordInitializationStates(flowInfo); 114 return flowInfo; 115 } 116 117 FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak); 119 mergedInitStateIndex = 120 currentScope.methodScope().recordInitializationStates(mergedInfo); 121 return mergedInfo; 122 } finally { 123 if (this.scope != null) this.scope.enclosingCase = null; } 125 } 126 127 133 public void generateCode(BlockScope currentScope, CodeStream codeStream) { 134 135 try { 136 if ((bits & IsReachable) == 0) { 137 return; 138 } 139 int pc = codeStream.position; 140 141 this.breakLabel.initialize(codeStream); 143 CaseLabel[] caseLabels = new CaseLabel[this.caseCount]; 144 boolean needSwitch = this.caseCount != 0; 145 for (int i = 0; i < caseCount; i++) { 146 cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream)); 147 caseLabels[i].tagBits |= BranchLabel.USED; 148 } 149 CaseLabel defaultLabel = new CaseLabel(codeStream); 150 if (needSwitch) defaultLabel.tagBits |= BranchLabel.USED; 151 if (defaultCase != null) { 152 defaultCase.targetLabel = defaultLabel; 153 } 154 155 final TypeBinding resolvedType = this.expression.resolvedType; 156 if (resolvedType.isEnum()) { 157 if (needSwitch) { 158 codeStream.invokestatic(this.synthetic); 160 expression.generateCode(currentScope, codeStream, true); 161 codeStream.invokeEnumOrdinal(resolvedType.constantPoolName()); 163 codeStream.iaload(); 164 } else { 165 expression.generateCode(currentScope, codeStream, false); 167 } 168 } else { 169 expression.generateCode(currentScope, codeStream, needSwitch); } 172 if (needSwitch) { 174 int[] sortedIndexes = new int[this.caseCount]; 175 for (int i = 0; i < caseCount; i++) { 177 sortedIndexes[i] = i; 178 } 179 int[] localKeysCopy; 180 System.arraycopy(this.constants, 0, (localKeysCopy = new int[this.caseCount]), 0, this.caseCount); 181 CodeStream.sort(localKeysCopy, 0, this.caseCount - 1, sortedIndexes); 182 183 int max = localKeysCopy[this.caseCount - 1]; 184 int min = localKeysCopy[0]; 185 if ((long) (caseCount * 2.5) > ((long) max - (long) min)) { 186 187 if (max > 0x7FFF0000 && currentScope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_4) { 190 codeStream.lookupswitch(defaultLabel, this.constants, sortedIndexes, caseLabels); 191 192 } else { 193 codeStream.tableswitch( 194 defaultLabel, 195 min, 196 max, 197 this.constants, 198 sortedIndexes, 199 caseLabels); 200 } 201 } else { 202 codeStream.lookupswitch(defaultLabel, this.constants, sortedIndexes, caseLabels); 203 } 204 codeStream.updateLastRecordedEndPC(this.scope, codeStream.position); 205 } 206 207 int caseIndex = 0; 209 if (this.statements != null) { 210 for (int i = 0, maxCases = this.statements.length; i < maxCases; i++) { 211 Statement statement = this.statements[i]; 212 if ((caseIndex < this.caseCount) && (statement == this.cases[caseIndex])) { this.scope.enclosingCase = this.cases[caseIndex]; if (preSwitchInitStateIndex != -1) { 215 codeStream.removeNotDefinitelyAssignedVariables(currentScope, preSwitchInitStateIndex); 216 } 217 caseIndex++; 218 } else { 219 if (statement == this.defaultCase) { this.scope.enclosingCase = this.defaultCase; if (preSwitchInitStateIndex != -1) { 222 codeStream.removeNotDefinitelyAssignedVariables(currentScope, preSwitchInitStateIndex); 223 } 224 } 225 } 226 statement.generateCode(scope, codeStream); 227 } 228 } 229 if (mergedInitStateIndex != -1) { 231 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 232 codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 233 } 234 if (scope != currentScope) { 235 codeStream.exitUserScope(this.scope); 236 } 237 this.breakLabel.place(); 239 if (defaultCase == null) { 240 codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd, true); 242 defaultLabel.place(); 243 } 244 codeStream.recordPositionsFrom(pc, this.sourceStart); 245 } finally { 246 if (this.scope != null) this.scope.enclosingCase = null; } 248 } 249 250 public StringBuffer printStatement(int indent, StringBuffer output) { 251 252 printIndent(indent, output).append("switch ("); expression.printExpression(0, output).append(") {"); if (statements != null) { 255 for (int i = 0; i < statements.length; i++) { 256 output.append('\n'); 257 if (statements[i] instanceof CaseStatement) { 258 statements[i].printStatement(indent, output); 259 } else { 260 statements[i].printStatement(indent+2, output); 261 } 262 } 263 } 264 output.append("\n"); return printIndent(indent, output).append('}'); 266 } 267 268 public void resolve(BlockScope upperScope) { 269 270 try { 271 boolean isEnumSwitch = false; 272 TypeBinding expressionType = expression.resolveType(upperScope); 273 if (expressionType != null) { 274 expression.computeConversion(upperScope, expressionType, expressionType); 275 checkType: { 276 if (expressionType.isBaseType()) { 277 if (expression.isConstantValueOfTypeAssignableToType(expressionType, TypeBinding.INT)) 278 break checkType; 279 if (expressionType.isCompatibleWith(TypeBinding.INT)) 280 break checkType; 281 } else if (expressionType.isEnum()) { 282 isEnumSwitch = true; 283 break checkType; 284 } else if (upperScope.isBoxingCompatibleWith(expressionType, TypeBinding.INT)) { 285 expression.computeConversion(upperScope, TypeBinding.INT, expressionType); 286 break checkType; 287 } 288 upperScope.problemReporter().incorrectSwitchType(expression, expressionType); 289 expressionType = null; } 291 } 292 if (statements != null) { 293 scope = new BlockScope(upperScope); 294 int length; 295 cases = new CaseStatement[length = statements.length]; 297 this.constants = new int[length]; 298 CaseStatement[] duplicateCaseStatements = null; 299 int duplicateCaseStatementsCounter = 0; 300 int counter = 0; 301 for (int i = 0; i < length; i++) { 302 Constant constant; 303 final Statement statement = statements[i]; 304 if ((constant = statement.resolveCase(scope, expressionType, this)) != Constant.NotAConstant) { 305 int key = constant.intValue(); 306 for (int j = 0; j < counter; j++) { 308 if (this.constants[j] == key) { 309 final CaseStatement currentCaseStatement = (CaseStatement) statement; 310 if (duplicateCaseStatements == null) { 311 scope.problemReporter().duplicateCase(cases[j]); 312 scope.problemReporter().duplicateCase(currentCaseStatement); 313 duplicateCaseStatements = new CaseStatement[length]; 314 duplicateCaseStatements[duplicateCaseStatementsCounter++] = cases[j]; 315 duplicateCaseStatements[duplicateCaseStatementsCounter++] = currentCaseStatement; 316 } else { 317 boolean found = false; 318 searchReportedDuplicate: for (int k = 2; k < duplicateCaseStatementsCounter; k++) { 319 if (duplicateCaseStatements[k] == statement) { 320 found = true; 321 break searchReportedDuplicate; 322 } 323 } 324 if (!found) { 325 scope.problemReporter().duplicateCase(currentCaseStatement); 326 duplicateCaseStatements[duplicateCaseStatementsCounter++] = currentCaseStatement; 327 } 328 } 329 } 330 } 331 this.constants[counter++] = key; 332 } 333 } 334 if (length != counter) { System.arraycopy(this.constants, 0, this.constants = new int[counter], 0, counter); 336 } 337 } else { 338 if ((this.bits & UndocumentedEmptyBlock) != 0) { 339 upperScope.problemReporter().undocumentedEmptyBlock(this.blockStart, this.sourceEnd); 340 } 341 } 342 if (isEnumSwitch && defaultCase == null 344 && upperScope.compilerOptions().getSeverity(CompilerOptions.IncompleteEnumSwitch) != ProblemSeverities.Ignore) { 345 int constantCount = this.constants == null ? 0 : this.constants.length; if (constantCount == caseCount && caseCount != ((ReferenceBinding)expressionType).enumConstantCount()) { 348 FieldBinding[] enumFields = ((ReferenceBinding)expressionType.erasure()).fields(); 349 for (int i = 0, max = enumFields.length; i <max; i++) { 350 FieldBinding enumConstant = enumFields[i]; 351 if ((enumConstant.modifiers & ClassFileConstants.AccEnum) == 0) continue; 352 findConstant : { 353 for (int j = 0; j < caseCount; j++) { 354 if ((enumConstant.id + 1) == this.constants[j]) break findConstant; 356 } 357 upperScope.problemReporter().missingEnumConstantCase(this, enumConstant); 359 } 360 } 361 } 362 } 363 } finally { 364 if (this.scope != null) this.scope.enclosingCase = null; } 366 } 367 368 public void traverse( 369 ASTVisitor visitor, 370 BlockScope blockScope) { 371 372 if (visitor.visit(this, blockScope)) { 373 expression.traverse(visitor, scope); 374 if (statements != null) { 375 int statementsLength = statements.length; 376 for (int i = 0; i < statementsLength; i++) 377 statements[i].traverse(visitor, scope); 378 } 379 } 380 visitor.endVisit(this, blockScope); 381 } 382 383 386 public void branchChainTo(BranchLabel label) { 387 388 if (this.breakLabel.forwardReferenceCount() > 0) { 394 label.becomeDelegateFor(this.breakLabel); 395 } 396 } 397 } 398 | Popular Tags |