1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
19 public class FieldDeclaration extends AbstractVariableDeclaration {
21 public FieldBinding binding;
22 boolean hasBeenResolved = false;
23 public Javadoc javadoc;
25 //allows to retrieve both the "type" part of the declaration (part1)
26 //and also the part that decribe the name and the init and optionally
27 //some other dimension ! ....
28 //public int[] a, b[] = X, c ;
29 //for b that would give for
30 // - part1 : public int[]
33 public int endPart1Position;
34 public int endPart2Position;
36 public FieldDeclaration() {
37 // for subtypes or conversion
40 public FieldDeclaration(
47 //due to some declaration like
48 // int x, y = 3, z , x ;
49 //the sourceStart and the sourceEnd is ONLY on the name
50 this.sourceStart = sourceStart;
51 this.sourceEnd = sourceEnd;
54 public FlowInfo analyseCode(
55 MethodScope initializationScope,
56 FlowContext flowContext,
59 if (this.binding != null && this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
60 if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
61 initializationScope.problemReporter().unusedPrivateField(this);
64 // cannot define static non-constant field inside nested class
65 if (this.binding != null
66 && this.binding.isValidBinding()
67 && this.binding.isStatic()
68 && !this.binding.isConstantValue()
69 && this.binding.declaringClass.isNestedType()
70 && this.binding.declaringClass.isClass()
71 && !this.binding.declaringClass.isStatic()) {
72 initializationScope.problemReporter().unexpectedStaticModifierForField(
73 (SourceTypeBinding) this.binding.declaringClass,
77 checkAnnotationField: {
78 if (!this.binding.declaringClass.isAnnotationType())
79 break checkAnnotationField;
80 if (this.initialization != null) {
81 if (this.binding.type.isArrayType() && (this.initialization instanceof ArrayInitializer))
82 break checkAnnotationField;
83 if (this.initialization.constant != NotAConstant)
84 break checkAnnotationField;
86 initializationScope.problemReporter().annotationFieldNeedConstantInitialization(this);
88 if (this.initialization != null) {
91 .analyseCode(initializationScope, flowContext, flowInfo)
92 .unconditionalInits();
93 flowInfo.markAsDefinitelyAssigned(this.binding);
99 * Code generation for a field declaration:
100 * standard assignment to a field
102 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
103 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
105 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
107 if ((this.bits & IsReachableMASK) == 0) {
110 // do not generate initialization code if final and static (constant is then
111 // recorded inside the field itself).
112 int pc = codeStream.position;
114 if (this.initialization != null
115 && !((isStatic = this.binding.isStatic()) && this.binding.isConstantValue())) {
116 // non-static field, need receiver
118 codeStream.aload_0();
119 // generate initialization value
120 this.initialization.generateCode(currentScope, codeStream, true);
123 codeStream.putstatic(this.binding);
125 codeStream.putfield(this.binding);
128 codeStream.recordPositionsFrom(pc, this.sourceStart);
132 * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind()
134 public int getKind() {
135 return this.type == null ? ENUM_CONSTANT : FIELD;
138 public boolean isStatic() {
140 if (this.binding != null)
141 return this.binding.isStatic();
142 return (this.modifiers & AccStatic) != 0;
145 public void resolve(MethodScope initializationScope) {
147 // the two <constant = Constant.NotAConstant> could be regrouped into
148 // a single line but it is clearer to have two lines while the reason of their
149 // existence is not at all the same. See comment for the second one.
151 //--------------------------------------------------------
152 if (!this.hasBeenResolved && this.binding != null && this.binding.isValidBinding()) {
154 this.hasBeenResolved = true;
156 resolveAnnotations(initializationScope, this.annotations, this.binding);
158 // check if field is hiding some variable - issue is that field binding already got inserted in scope
159 // thus must lookup separately in super type and outer context
160 ClassScope classScope = initializationScope.enclosingClassScope();
162 if (classScope != null) {
163 SourceTypeBinding declaringType = classScope.enclosingSourceType();
164 boolean checkLocal = true;
165 if (declaringType.superclass != null) {
166 Binding existingVariable = classScope.findField(declaringType.superclass, this.name, this, false /*do not resolve hidden field*/);
167 if (existingVariable != null && this.binding != existingVariable && existingVariable.isValidBinding()){
168 initializationScope.problemReporter().fieldHiding(this, existingVariable);
169 checkLocal = false; // already found a matching field
173 Scope outerScope = classScope.parent;
174 // only corner case is: lookup of outer field through static declaringType, which isn't detected by #getBinding as lookup starts
175 // from outer scope. Subsequent static contexts are detected for free.
176 Binding existingVariable = outerScope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/);
177 if (existingVariable != null && this.binding != existingVariable && existingVariable.isValidBinding()
178 && (!(existingVariable instanceof FieldBinding)
179 || ((FieldBinding) existingVariable).isStatic()
180 || !declaringType.isStatic())) {
181 initializationScope.problemReporter().fieldHiding(this, existingVariable);
186 if (this.type != null ) { // enum constants have no declared type
187 this.type.resolvedType = this.binding.type; // update binding for type reference
190 FieldBinding previousField = initializationScope.initializedField;
191 int previousFieldID = initializationScope.lastVisibleFieldID;
193 initializationScope.initializedField = this.binding;
194 initializationScope.lastVisibleFieldID = this.binding.id;
196 // the resolution of the initialization hasn't been done
197 if (this.initialization == null) {
198 this.binding.setConstant(Constant.NotAConstant);
200 // break dead-lock cycles by forcing constant to NotAConstant
201 this.binding.setConstant(Constant.NotAConstant);
203 TypeBinding fieldType = this.binding.type;
204 TypeBinding initializationType;
205 this.initialization.setExpectedType(fieldType); // needed in case of generic method invocation
206 if (this.initialization instanceof ArrayInitializer) {
208 if ((initializationType = this.initialization.resolveTypeExpecting(initializationScope, fieldType)) != null) {
209 ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationType;
210 this.initialization.computeConversion(initializationScope, fieldType, initializationType);
212 } else if ((initializationType = this.initialization.resolveType(initializationScope)) != null) {
214 if (fieldType != initializationType) // must call before computeConversion() and typeMismatchError()
215 initializationScope.compilationUnitScope().recordTypeConversion(fieldType, initializationType);
216 if (this.initialization.isConstantValueOfTypeAssignableToType(initializationType, fieldType)
217 || (fieldType.isBaseType() && BaseTypeBinding.isWidening(fieldType.id, initializationType.id))
218 || initializationType.isCompatibleWith(fieldType)) {
219 this.initialization.computeConversion(initializationScope, fieldType, initializationType);
220 if (initializationType.needsUncheckedConversion(fieldType)) {
221 initializationScope.problemReporter().unsafeRawConversion(this.initialization, initializationType, fieldType);
223 } else if (initializationScope.environment().options.sourceLevel >= JDK1_5 // autoboxing
224 && (initializationScope.isBoxingCompatibleWith(initializationType, fieldType)
225 || (initializationType.isBaseType() // narrowing then boxing ?
226 && initializationType != null
227 && !fieldType.isBaseType()
228 && initialization.isConstantValueOfTypeAssignableToType(initializationType, initializationScope.environment().computeBoxingType(fieldType))))) {
229 this.initialization.computeConversion(initializationScope, fieldType, initializationType);
231 initializationScope.problemReporter().typeMismatchError(initializationType, fieldType, this);
233 if (this.binding.isFinal()){ // cast from constant actual type to variable type
234 this.binding.setConstant(this.initialization.constant.castTo((this.binding.type.id << 4) + this.initialization.constant.typeID()));
237 this.binding.setConstant(NotAConstant);
240 // Resolve Javadoc comment if one is present
241 if (this.javadoc != null) {
243 if (classScope != null) {
244 this.javadoc.resolve(classScope);
247 this.javadoc.resolve(initializationScope);
248 } else if (this.binding != null && this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) {
249 initializationScope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers);
252 initializationScope.initializedField = previousField;
253 initializationScope.lastVisibleFieldID = previousFieldID;
254 if (this.binding.constant() == null)
255 this.binding.setConstant(Constant.NotAConstant);
260 public void traverse(ASTVisitor visitor, MethodScope scope) {
262 if (visitor.visit(this, scope)) {
263 if (this.annotations != null) {
264 int annotationsLength = this.annotations.length;
265 for (int i = 0; i < annotationsLength; i++)
266 this.annotations[i].traverse(visitor, scope);
268 if (this.type != null) {
269 this.type.traverse(visitor, scope);
271 if (this.initialization != null)
272 this.initialization.traverse(visitor, scope);
274 visitor.endVisit(this, scope);