001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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.impl.*;
014: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
015: import org.eclipse.jdt.internal.compiler.codegen.*;
016: import org.eclipse.jdt.internal.compiler.flow.*;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class LocalDeclaration extends AbstractVariableDeclaration {
020:
021: public LocalVariableBinding binding;
022:
023: public LocalDeclaration(char[] name, int sourceStart, int sourceEnd) {
024:
025: this .name = name;
026: this .sourceStart = sourceStart;
027: this .sourceEnd = sourceEnd;
028: this .declarationEnd = sourceEnd;
029: }
030:
031: public FlowInfo analyseCode(BlockScope currentScope,
032: FlowContext flowContext, FlowInfo flowInfo) {
033: // record variable initialization if any
034: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
035: bits |= ASTNode.IsLocalDeclarationReachable; // only set if actually reached
036: }
037: if (this .initialization == null) {
038: return flowInfo;
039: }
040: int nullStatus = this .initialization.nullStatus(flowInfo);
041: flowInfo = this .initialization.analyseCode(currentScope,
042: flowContext, flowInfo).unconditionalInits();
043: if (!flowInfo.isDefinitelyAssigned(this .binding)) {// for local variable debug attributes
044: this .bits |= FirstAssignmentToLocal;
045: } else {
046: this .bits &= ~FirstAssignmentToLocal; // int i = (i = 0);
047: }
048: flowInfo.markAsDefinitelyAssigned(binding);
049: if ((this .binding.type.tagBits & TagBits.IsBaseType) == 0) {
050: switch (nullStatus) {
051: case FlowInfo.NULL:
052: flowInfo.markAsDefinitelyNull(this .binding);
053: break;
054: case FlowInfo.NON_NULL:
055: flowInfo.markAsDefinitelyNonNull(this .binding);
056: break;
057: default:
058: flowInfo.markAsDefinitelyUnknown(this .binding);
059: }
060: // no need to inform enclosing try block since its locals won't get
061: // known by the finally block
062: }
063: return flowInfo;
064: }
065:
066: public void checkModifiers() {
067:
068: //only potential valid modifier is <<final>>
069: if (((modifiers & ExtraCompilerModifiers.AccJustFlag) & ~ClassFileConstants.AccFinal) != 0)
070: //AccModifierProblem -> other (non-visibility problem)
071: //AccAlternateModifierProblem -> duplicate modifier
072: //AccModifierProblem | AccAlternateModifierProblem -> visibility problem"
073:
074: modifiers = (modifiers & ~ExtraCompilerModifiers.AccAlternateModifierProblem)
075: | ExtraCompilerModifiers.AccModifierProblem;
076: }
077:
078: /**
079: * Code generation for a local declaration:
080: * i.e. normal assignment to a local variable + unused variable handling
081: */
082: public void generateCode(BlockScope currentScope,
083: CodeStream codeStream) {
084:
085: // even if not reachable, variable must be added to visible if allocated (28298)
086: if (binding.resolvedPosition != -1) {
087: codeStream.addVisibleLocalVariable(binding);
088: }
089: if ((bits & IsReachable) == 0) {
090: return;
091: }
092: int pc = codeStream.position;
093:
094: // something to initialize?
095: generateInit: {
096: if (this .initialization == null)
097: break generateInit;
098: // forget initializing unused or final locals set to constant value (final ones are inlined)
099: if (binding.resolvedPosition < 0) {
100: if (initialization.constant != Constant.NotAConstant)
101: break generateInit;
102: // if binding unused generate then discard the value
103: initialization.generateCode(currentScope, codeStream,
104: false);
105: break generateInit;
106: }
107: initialization.generateCode(currentScope, codeStream, true);
108: // 26903, need extra cast to store null in array local var
109: if (binding.type.isArrayType()
110: && (initialization.resolvedType == TypeBinding.NULL // arrayLoc = null
111: || ((initialization instanceof CastExpression) // arrayLoc = (type[])null
112: && (((CastExpression) initialization)
113: .innermostCastedExpression().resolvedType == TypeBinding.NULL)))) {
114: codeStream.checkcast(binding.type);
115: }
116: codeStream.store(binding, false);
117: if ((this .bits & ASTNode.FirstAssignmentToLocal) != 0) {
118: /* Variable may have been initialized during the code initializing it
119: e.g. int i = (i = 1);
120: */
121: binding
122: .recordInitializationStartPC(codeStream.position);
123: }
124: }
125: codeStream.recordPositionsFrom(pc, this .sourceStart);
126: }
127:
128: /**
129: * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind()
130: */
131: public int getKind() {
132: return LOCAL_VARIABLE;
133: }
134:
135: public void resolve(BlockScope scope) {
136:
137: // create a binding and add it to the scope
138: TypeBinding variableType = type
139: .resolveType(scope, true /* check bounds*/);
140:
141: checkModifiers();
142: if (variableType != null) {
143: if (variableType == TypeBinding.VOID) {
144: scope.problemReporter().variableTypeCannotBeVoid(this );
145: return;
146: }
147: if (variableType.isArrayType()
148: && ((ArrayBinding) variableType).leafComponentType == TypeBinding.VOID) {
149: scope.problemReporter().variableTypeCannotBeVoidArray(
150: this );
151: return;
152: }
153: }
154:
155: Binding existingVariable = scope
156: .getBinding(name, Binding.VARIABLE, this , false /*do not resolve hidden field*/);
157: if (existingVariable != null
158: && existingVariable.isValidBinding()) {
159: if (existingVariable instanceof LocalVariableBinding
160: && this .hiddenVariableDepth == 0) {
161: scope.problemReporter().redefineLocal(this );
162: } else {
163: scope.problemReporter().localVariableHiding(this ,
164: existingVariable, false);
165: }
166: }
167:
168: if ((modifiers & ClassFileConstants.AccFinal) != 0
169: && this .initialization == null) {
170: modifiers |= ExtraCompilerModifiers.AccBlankFinal;
171: }
172: this .binding = new LocalVariableBinding(this , variableType,
173: modifiers, false);
174: scope.addLocalVariable(binding);
175: this .binding.setConstant(Constant.NotAConstant);
176: // allow to recursivelly target the binding....
177: // the correct constant is harmed if correctly computed at the end of this method
178:
179: if (variableType == null) {
180: if (initialization != null)
181: initialization.resolveType(scope); // want to report all possible errors
182: return;
183: }
184:
185: // store the constant for final locals
186: if (initialization != null) {
187: if (initialization instanceof ArrayInitializer) {
188: TypeBinding initializationType = initialization
189: .resolveTypeExpecting(scope, variableType);
190: if (initializationType != null) {
191: ((ArrayInitializer) initialization).binding = (ArrayBinding) initializationType;
192: initialization.computeConversion(scope,
193: variableType, initializationType);
194: }
195: } else {
196: this .initialization.setExpectedType(variableType);
197: TypeBinding initializationType = this .initialization
198: .resolveType(scope);
199: if (initializationType != null) {
200: if (variableType != initializationType) // must call before computeConversion() and typeMismatchError()
201: scope.compilationUnitScope()
202: .recordTypeConversion(variableType,
203: initializationType);
204: if (initialization
205: .isConstantValueOfTypeAssignableToType(
206: initializationType, variableType)
207: || (variableType.isBaseType() && BaseTypeBinding
208: .isWidening(variableType.id,
209: initializationType.id))
210: || initializationType
211: .isCompatibleWith(variableType)) {
212: this .initialization.computeConversion(scope,
213: variableType, initializationType);
214: if (initializationType
215: .needsUncheckedConversion(variableType)) {
216: scope.problemReporter()
217: .unsafeTypeConversion(
218: this .initialization,
219: initializationType,
220: variableType);
221: }
222: if (this .initialization instanceof CastExpression
223: && (this .initialization.bits & ASTNode.UnnecessaryCast) == 0) {
224: CastExpression
225: .checkNeedForAssignedCast(
226: scope,
227: variableType,
228: (CastExpression) this .initialization);
229: }
230: } else if (scope.isBoxingCompatibleWith(
231: initializationType, variableType)
232: || (initializationType.isBaseType() // narrowing then boxing ?
233: && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
234: && !variableType.isBaseType() && initialization
235: .isConstantValueOfTypeAssignableToType(
236: initializationType,
237: scope
238: .environment()
239: .computeBoxingType(
240: variableType)))) {
241: this .initialization.computeConversion(scope,
242: variableType, initializationType);
243: if (this .initialization instanceof CastExpression
244: && (this .initialization.bits & ASTNode.UnnecessaryCast) == 0) {
245: CastExpression
246: .checkNeedForAssignedCast(
247: scope,
248: variableType,
249: (CastExpression) this .initialization);
250: }
251: } else {
252: scope.problemReporter().typeMismatchError(
253: initializationType, variableType,
254: this .initialization);
255: }
256: }
257: }
258: // check for assignment with no effect
259: if (this .binding == Assignment
260: .getDirectBinding(this .initialization)) {
261: scope.problemReporter().assignmentHasNoEffect(this ,
262: this .name);
263: }
264: // change the constant in the binding when it is final
265: // (the optimization of the constant propagation will be done later on)
266: // cast from constant actual type to variable type
267: binding
268: .setConstant(binding.isFinal() ? initialization.constant
269: .castTo((variableType.id << 4)
270: + initialization.constant.typeID())
271: : Constant.NotAConstant);
272: }
273: // only resolve annotation at the end, for constant to be positionned before (96991)
274: resolveAnnotations(scope, this .annotations, this .binding);
275: }
276:
277: public void traverse(ASTVisitor visitor, BlockScope scope) {
278:
279: if (visitor.visit(this , scope)) {
280: if (this .annotations != null) {
281: int annotationsLength = this .annotations.length;
282: for (int i = 0; i < annotationsLength; i++)
283: this.annotations[i].traverse(visitor, scope);
284: }
285: type.traverse(visitor, scope);
286: if (initialization != null)
287: initialization.traverse(visitor, scope);
288: }
289: visitor.endVisit(this, scope);
290: }
291: }
|