blob: fb727f92ac3449c3a2d424f8bba60e195fdf3e24 [file] [log] [blame]
package org.eclipse.jdt.internal.compiler.ast;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor;
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
public class FieldDeclaration extends AbstractVariableDeclaration {
public FieldBinding binding;
boolean hasBeenResolved = false;
//allows to retrieve both the "type" part of the declaration (part1)
//and also the part that decribe the name and the init and optionally
//some other dimension ! ....
//public int[] a, b[] = X, c ;
//for b that would give for
// - part1 : public int[]
// - part2 : b[] = X,
public int endPart1Position;
public int endPart2Position;
public FieldDeclaration(){}
public FieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) {
this.initialization = initialization;
this.name = name;
//due to some declaration like
// int x, y = 3, z , x ;
//the sourceStart and the sourceEnd is ONLY on the name
this.sourceStart = sourceStart;
this.sourceEnd = sourceEnd;
}
public FlowInfo analyseCode(MethodScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
if (initialization != null) {
flowInfo = initialization.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
flowInfo.markAsDefinitelyAssigned(binding);
} else {
flowInfo.markAsDefinitelyNotAssigned(binding); // clear the bit in case it was already set (from enclosing info)
}
return flowInfo;
}
/**
* Code generation for a field declaration
* i.e. normal assignment to a field
*
* @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
* @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
*/
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
if ((bits & IsReachableMASK) == 0) {
return;
}
// do not generate initialization code if final and static (constant is then
// recorded inside the field itself).
int pc = codeStream.position;
boolean isStatic;
if (initialization != null
&& !((isStatic = binding.isStatic()) && binding.constant != NotAConstant)){
// non-static field, need receiver
if (!isStatic) codeStream.aload_0();
// generate initialization value
initialization.generateCode(currentScope, codeStream, true);
// store into field
if (isStatic) {
codeStream.putstatic(binding);
} else {
codeStream.putfield(binding);
}
}
codeStream.recordPositionsFrom(pc, this);
}
public TypeBinding getTypeBinding(Scope scope) {
return type.getTypeBinding(scope);
}
public boolean isField() {
return true;
}
public boolean isStatic() {
if (binding != null) return binding.isStatic();
return (modifiers & AccStatic) != 0;
}
public String name(){
return String.valueOf(name) ;}
public void resolve(MethodScope initializationScope) {
// the two <constant = Constant.NotAConstant> could be regrouped into
// a single line but it is clearer to have two lines while the reason of their
// existence is not at all the same. See comment for the second one.
//--------------------------------------------------------
if (!hasBeenResolved && binding != null && binding.isValidBinding()) {
hasBeenResolved = true;
if (isTypeUseDeprecated(binding.type, initializationScope))
initializationScope.problemReporter().deprecatedType(binding.type, type);
this.type.binding = this.binding.type; // update binding for type reference
// the resolution of the initialization hasn't been done
if (initialization == null) {
binding.constant = Constant.NotAConstant;
} else {
// break dead-lock cycles by forcing constant to NotAConstant
int previous = initializationScope.fieldDeclarationIndex;
try {
initializationScope.fieldDeclarationIndex = binding.id;
binding.constant = Constant.NotAConstant;
TypeBinding tb = binding.type;
TypeBinding initTb;
if (initialization instanceof ArrayInitializer) {
if ((initTb = initialization.resolveTypeExpecting(initializationScope, tb)) != null) {
((ArrayInitializer) initialization).binding = (ArrayBinding) initTb;
initialization.implicitWidening(tb, initTb);
}
} else if ((initTb = initialization.resolveType(initializationScope)) != null) {
if (initialization.isConstantValueOfTypeAssignableToType(initTb, tb) || (tb.isBaseType() && BaseTypeBinding.isWidening(tb.id, initTb.id)))
initialization.implicitWidening(tb, initTb);
else if (initializationScope.areTypesCompatible(initTb, tb))
initialization.implicitWidening(tb, initTb);
else
initializationScope.problemReporter().typeMismatchError(initTb, tb, this);
if (binding.isFinal()) // cast from constant actual type to variable type
binding.constant = initialization.constant.castTo((binding.type.id << 4) + initialization.constant.typeID());
} else {
binding.constant = NotAConstant;
}
} finally {
initializationScope.fieldDeclarationIndex = previous;
if (binding.constant == null) binding.constant = Constant.NotAConstant;
}
}
// cannot define static non-constant field inside nested class
if (binding.isStatic() && binding.constant == NotAConstant)
if (binding.declaringClass.isNestedType() && binding.declaringClass.isClass() && !binding.declaringClass.isStatic())
initializationScope.problemReporter().unexpectedStaticModifierForField((SourceTypeBinding)binding.declaringClass, this);
}
}
public void traverse(IAbstractSyntaxTreeVisitor visitor, MethodScope scope) {
visitor.visit(this, scope);
type.traverse(visitor, scope);
if (initialization != null) initialization.traverse(visitor, scope);
}
}