001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
014: import org.eclipse.jdt.internal.compiler.codegen.CaseLabel;
015: import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
016: import org.eclipse.jdt.internal.compiler.flow.FlowContext;
017: import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
018: import org.eclipse.jdt.internal.compiler.impl.Constant;
019: import org.eclipse.jdt.internal.compiler.impl.IntConstant;
020: import org.eclipse.jdt.internal.compiler.lookup.Binding;
021: import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
022: import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
023: import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
024: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
025:
026: public class CaseStatement extends Statement {
027:
028: public Expression constantExpression;
029: public CaseLabel targetLabel;
030:
031: public CaseStatement(Expression constantExpression, int sourceEnd,
032: int sourceStart) {
033: this .constantExpression = constantExpression;
034: this .sourceEnd = sourceEnd;
035: this .sourceStart = sourceStart;
036: }
037:
038: public FlowInfo analyseCode(BlockScope currentScope,
039: FlowContext flowContext, FlowInfo flowInfo) {
040:
041: if (this .constantExpression != null) {
042: if (this .constantExpression.constant == Constant.NotAConstant
043: && !this .constantExpression.resolvedType.isEnum()) {
044: currentScope.problemReporter()
045: .caseExpressionMustBeConstant(
046: this .constantExpression);
047: }
048: this .constantExpression.analyseCode(currentScope,
049: flowContext, flowInfo);
050: }
051: return flowInfo;
052: }
053:
054: public StringBuffer printStatement(int tab, StringBuffer output) {
055: printIndent(tab, output);
056: if (this .constantExpression == null) {
057: output.append("default : "); //$NON-NLS-1$
058: } else {
059: output.append("case "); //$NON-NLS-1$
060: this .constantExpression.printExpression(0, output).append(
061: " : "); //$NON-NLS-1$
062: }
063: return output.append(';');
064: }
065:
066: /**
067: * Case code generation
068: *
069: */
070: public void generateCode(BlockScope currentScope,
071: CodeStream codeStream) {
072: if ((this .bits & ASTNode.IsReachable) == 0) {
073: return;
074: }
075: int pc = codeStream.position;
076: this .targetLabel.place();
077: codeStream.recordPositionsFrom(pc, this .sourceStart);
078: }
079:
080: /**
081: * No-op : should use resolveCase(...) instead.
082: */
083: public void resolve(BlockScope scope) {
084: // no-op : should use resolveCase(...) instead.
085: }
086:
087: /**
088: * Returns the constant intValue or ordinal for enum constants. If constant is NotAConstant, then answers Float.MIN_VALUE
089: * @see org.eclipse.jdt.internal.compiler.ast.Statement#resolveCase(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.ast.SwitchStatement)
090: */
091: public Constant resolveCase(BlockScope scope,
092: TypeBinding switchExpressionType,
093: SwitchStatement switchStatement) {
094: // switchExpressionType maybe null in error case
095: scope.enclosingCase = this ; // record entering in a switch case block
096:
097: if (this .constantExpression == null) {
098: // remember the default case into the associated switch statement
099: if (switchStatement.defaultCase != null)
100: scope.problemReporter().duplicateDefaultCase(this );
101:
102: // on error the last default will be the selected one ...
103: switchStatement.defaultCase = this ;
104: return Constant.NotAConstant;
105: }
106: // add into the collection of cases of the associated switch statement
107: switchStatement.cases[switchStatement.caseCount++] = this ;
108: // tag constant name with enum type for privileged access to its members
109: if (switchExpressionType != null
110: && switchExpressionType.isEnum()
111: && (this .constantExpression instanceof SingleNameReference)) {
112: ((SingleNameReference) this .constantExpression)
113: .setActualReceiverType((ReferenceBinding) switchExpressionType);
114: }
115: TypeBinding caseType = this .constantExpression
116: .resolveType(scope);
117: if (caseType == null || switchExpressionType == null)
118: return Constant.NotAConstant;
119: if (this .constantExpression
120: .isConstantValueOfTypeAssignableToType(caseType,
121: switchExpressionType)
122: || caseType.isCompatibleWith(switchExpressionType)) {
123: if (caseType.isEnum()) {
124: if (((this .constantExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
125: scope
126: .problemReporter()
127: .enumConstantsCannotBeSurroundedByParenthesis(
128: this .constantExpression);
129: }
130:
131: if (this .constantExpression instanceof NameReference
132: && (this .constantExpression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
133: NameReference reference = (NameReference) this .constantExpression;
134: FieldBinding field = reference.fieldBinding();
135: if ((field.modifiers & ClassFileConstants.AccEnum) == 0) {
136: scope.problemReporter()
137: .enumSwitchCannotTargetField(reference,
138: field);
139: } else if (reference instanceof QualifiedNameReference) {
140: scope
141: .problemReporter()
142: .cannotUseQualifiedEnumConstantInCaseLabel(
143: reference, field);
144: }
145: return IntConstant
146: .fromValue(field.original().id + 1); // (ordinal value + 1) zero should not be returned see bug 141810
147: }
148: } else {
149: return this .constantExpression.constant;
150: }
151: } else if (scope.isBoxingCompatibleWith(caseType,
152: switchExpressionType)
153: || (caseType.isBaseType() // narrowing then boxing ?
154: && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
155: && !switchExpressionType.isBaseType() && this .constantExpression
156: .isConstantValueOfTypeAssignableToType(
157: caseType, scope.environment()
158: .computeBoxingType(
159: switchExpressionType)))) {
160: // constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion
161: return this .constantExpression.constant;
162: }
163: scope.problemReporter().typeMismatchError(caseType,
164: switchExpressionType, this .constantExpression);
165: return Constant.NotAConstant;
166: }
167:
168: public void traverse(ASTVisitor visitor, BlockScope blockScope) {
169: if (visitor.visit(this, blockScope)) {
170: if (this.constantExpression != null)
171: this.constantExpression.traverse(visitor, blockScope);
172: }
173: visitor.endVisit(this, blockScope);
174: }
175: }
|