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.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 FieldDeclaration extends AbstractVariableDeclaration {
020:
021: public FieldBinding binding;
022: public Javadoc javadoc;
023:
024: //allows to retrieve both the "type" part of the declaration (part1)
025: //and also the part that decribe the name and the init and optionally
026: //some other dimension ! ....
027: //public int[] a, b[] = X, c ;
028: //for b that would give for
029: // - part1 : public int[]
030: // - part2 : b[] = X,
031:
032: public int endPart1Position;
033: public int endPart2Position;
034:
035: public FieldDeclaration() {
036: // for subtypes or conversion
037: }
038:
039: public FieldDeclaration(char[] name, int sourceStart, int sourceEnd) {
040: this .name = name;
041: //due to some declaration like
042: // int x, y = 3, z , x ;
043: //the sourceStart and the sourceEnd is ONLY on the name
044: this .sourceStart = sourceStart;
045: this .sourceEnd = sourceEnd;
046: }
047:
048: public FlowInfo analyseCode(MethodScope initializationScope,
049: FlowContext flowContext, FlowInfo flowInfo) {
050: if (this .binding != null && !this .binding.isUsed()) {
051: if (this .binding.isPrivate()
052: || (this .binding.declaringClass != null && this .binding.declaringClass
053: .isLocalType())) {
054: if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
055: initializationScope.problemReporter()
056: .unusedPrivateField(this );
057: }
058: }
059: }
060: // cannot define static non-constant field inside nested class
061: if (this .binding != null && this .binding.isValidBinding()
062: && this .binding.isStatic()
063: && this .binding.constant() == Constant.NotAConstant
064: && this .binding.declaringClass.isNestedType()
065: && !this .binding.declaringClass.isStatic()) {
066: initializationScope
067: .problemReporter()
068: .unexpectedStaticModifierForField(
069: (SourceTypeBinding) this .binding.declaringClass,
070: this );
071: }
072:
073: if (this .initialization != null) {
074: flowInfo = this .initialization.analyseCode(
075: initializationScope, flowContext, flowInfo)
076: .unconditionalInits();
077: flowInfo.markAsDefinitelyAssigned(this .binding);
078: }
079: return flowInfo;
080: }
081:
082: /**
083: * Code generation for a field declaration:
084: * standard assignment to a field
085: *
086: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
087: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
088: */
089: public void generateCode(BlockScope currentScope,
090: CodeStream codeStream) {
091: if ((this .bits & IsReachable) == 0) {
092: return;
093: }
094: // do not generate initialization code if final and static (constant is then
095: // recorded inside the field itself).
096: int pc = codeStream.position;
097: boolean isStatic;
098: if (this .initialization != null
099: && !((isStatic = this .binding.isStatic()) && this .binding
100: .constant() != Constant.NotAConstant)) {
101: // non-static field, need receiver
102: if (!isStatic)
103: codeStream.aload_0();
104: // generate initialization value
105: this .initialization.generateCode(currentScope, codeStream,
106: true);
107: // store into field
108: if (isStatic) {
109: codeStream.putstatic(this .binding);
110: } else {
111: codeStream.putfield(this .binding);
112: }
113: }
114: codeStream.recordPositionsFrom(pc, this .sourceStart);
115: }
116:
117: /**
118: * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind()
119: */
120: public int getKind() {
121: return this .type == null ? ENUM_CONSTANT : FIELD;
122: }
123:
124: public boolean isStatic() {
125: if (this .binding != null)
126: return this .binding.isStatic();
127: return (this .modifiers & ClassFileConstants.AccStatic) != 0;
128: }
129:
130: public StringBuffer printStatement(int indent, StringBuffer output) {
131: if (this .javadoc != null) {
132: this .javadoc.print(indent, output);
133: }
134: return super .printStatement(indent, output);
135: }
136:
137: public void resolve(MethodScope initializationScope) {
138: // the two <constant = Constant.NotAConstant> could be regrouped into
139: // a single line but it is clearer to have two lines while the reason of their
140: // existence is not at all the same. See comment for the second one.
141:
142: //--------------------------------------------------------
143: if ((this .bits & ASTNode.HasBeenResolved) != 0)
144: return;
145: if (this .binding == null || !this .binding.isValidBinding())
146: return;
147:
148: this .bits |= ASTNode.HasBeenResolved;
149:
150: // check if field is hiding some variable - issue is that field binding already got inserted in scope
151: // thus must lookup separately in super type and outer context
152: ClassScope classScope = initializationScope
153: .enclosingClassScope();
154:
155: if (classScope != null) {
156: checkHiding: {
157: SourceTypeBinding declaringType = classScope
158: .enclosingSourceType();
159: checkHidingSuperField: {
160: if (declaringType.super class == null)
161: break checkHidingSuperField;
162: Binding existingVariable = classScope.findField(
163: declaringType.super class, this .name, this ,
164: false /*do not resolve hidden field*/);
165: if (existingVariable == null)
166: break checkHidingSuperField; // keep checking outer scenario
167: if (!existingVariable.isValidBinding())
168: break checkHidingSuperField; // keep checking outer scenario
169: if (existingVariable instanceof FieldBinding) {
170: FieldBinding existingField = (FieldBinding) existingVariable;
171: if (existingField.original() == this .binding)
172: break checkHidingSuperField; // keep checking outer scenario
173: }
174: // collision with supertype field
175: initializationScope.problemReporter().fieldHiding(
176: this , existingVariable);
177: break checkHiding; // already found a matching field
178: }
179: // only corner case is: lookup of outer field through static declaringType, which isn't detected by #getBinding as lookup starts
180: // from outer scope. Subsequent static contexts are detected for free.
181: Scope outerScope = classScope.parent;
182: if (outerScope.kind == Scope.COMPILATION_UNIT_SCOPE)
183: break checkHiding;
184: Binding existingVariable = outerScope
185: .getBinding(this .name, Binding.VARIABLE, this ,
186: false /*do not resolve hidden field*/);
187: if (existingVariable == null)
188: break checkHiding;
189: if (!existingVariable.isValidBinding())
190: break checkHiding;
191: if (existingVariable == this .binding)
192: break checkHiding;
193: if (existingVariable instanceof FieldBinding) {
194: FieldBinding existingField = (FieldBinding) existingVariable;
195: if (existingField.original() == this .binding)
196: break checkHiding;
197: if (!existingField.isStatic()
198: && declaringType.isStatic())
199: break checkHiding;
200: }
201: // collision with outer field or local variable
202: initializationScope.problemReporter().fieldHiding(this ,
203: existingVariable);
204: }
205: }
206:
207: if (this .type != null) { // enum constants have no declared type
208: this .type.resolvedType = this .binding.type; // update binding for type reference
209: }
210:
211: FieldBinding previousField = initializationScope.initializedField;
212: int previousFieldID = initializationScope.lastVisibleFieldID;
213: try {
214: initializationScope.initializedField = this .binding;
215: initializationScope.lastVisibleFieldID = this .binding.id;
216:
217: resolveAnnotations(initializationScope, this .annotations,
218: this .binding);
219: // check @Deprecated annotation presence
220: if ((this .binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) == 0
221: && (this .binding.modifiers & ClassFileConstants.AccDeprecated) != 0
222: && initializationScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
223: initializationScope.problemReporter()
224: .missingDeprecatedAnnotationForField(this );
225: }
226: // the resolution of the initialization hasn't been done
227: if (this .initialization == null) {
228: this .binding.setConstant(Constant.NotAConstant);
229: } else {
230: // break dead-lock cycles by forcing constant to NotAConstant
231: this .binding.setConstant(Constant.NotAConstant);
232:
233: TypeBinding fieldType = this .binding.type;
234: TypeBinding initializationType;
235: this .initialization.setExpectedType(fieldType); // needed in case of generic method invocation
236: if (this .initialization instanceof ArrayInitializer) {
237:
238: if ((initializationType = this .initialization
239: .resolveTypeExpecting(initializationScope,
240: fieldType)) != null) {
241: ((ArrayInitializer) this .initialization).binding = (ArrayBinding) initializationType;
242: this .initialization.computeConversion(
243: initializationScope, fieldType,
244: initializationType);
245: }
246: } else if ((initializationType = this .initialization
247: .resolveType(initializationScope)) != null) {
248:
249: if (fieldType != initializationType) // must call before computeConversion() and typeMismatchError()
250: initializationScope.compilationUnitScope()
251: .recordTypeConversion(fieldType,
252: initializationType);
253: if (this .initialization
254: .isConstantValueOfTypeAssignableToType(
255: initializationType, fieldType)
256: || (fieldType.isBaseType() && BaseTypeBinding
257: .isWidening(fieldType.id,
258: initializationType.id))
259: || initializationType
260: .isCompatibleWith(fieldType)) {
261: this .initialization.computeConversion(
262: initializationScope, fieldType,
263: initializationType);
264: if (initializationType
265: .needsUncheckedConversion(fieldType)) {
266: initializationScope.problemReporter()
267: .unsafeTypeConversion(
268: this .initialization,
269: initializationType,
270: fieldType);
271: }
272: if (this .initialization instanceof CastExpression
273: && (this .initialization.bits & ASTNode.UnnecessaryCast) == 0) {
274: CastExpression
275: .checkNeedForAssignedCast(
276: initializationScope,
277: fieldType,
278: (CastExpression) this .initialization);
279: }
280: } else if (initializationScope
281: .isBoxingCompatibleWith(initializationType,
282: fieldType)
283: || (initializationType.isBaseType() // narrowing then boxing ?
284: && initializationScope
285: .compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
286: && !fieldType.isBaseType() && initialization
287: .isConstantValueOfTypeAssignableToType(
288: initializationType,
289: initializationScope
290: .environment()
291: .computeBoxingType(
292: fieldType)))) {
293: this .initialization.computeConversion(
294: initializationScope, fieldType,
295: initializationType);
296: if (this .initialization instanceof CastExpression
297: && (this .initialization.bits & ASTNode.UnnecessaryCast) == 0) {
298: CastExpression
299: .checkNeedForAssignedCast(
300: initializationScope,
301: fieldType,
302: (CastExpression) this .initialization);
303: }
304: } else {
305: initializationScope.problemReporter()
306: .typeMismatchError(initializationType,
307: fieldType, this );
308: }
309: if (this .binding.isFinal()) { // cast from constant actual type to variable type
310: this .binding
311: .setConstant(this .initialization.constant
312: .castTo((this .binding.type.id << 4)
313: + this .initialization.constant
314: .typeID()));
315: }
316: } else {
317: this .binding.setConstant(Constant.NotAConstant);
318: }
319: // check for assignment with no effect
320: if (this .binding == Assignment
321: .getDirectBinding(this .initialization)) {
322: initializationScope.problemReporter()
323: .assignmentHasNoEffect(this , this .name);
324: }
325: }
326: // Resolve Javadoc comment if one is present
327: if (this .javadoc != null) {
328: /*
329: if (classScope != null) {
330: this.javadoc.resolve(classScope);
331: }
332: */
333: this .javadoc.resolve(initializationScope);
334: } else if (this .binding.declaringClass != null
335: && !this .binding.declaringClass.isLocalType()) {
336: initializationScope.problemReporter().javadocMissing(
337: this .sourceStart, this .sourceEnd,
338: this .binding.modifiers);
339: }
340: } finally {
341: initializationScope.initializedField = previousField;
342: initializationScope.lastVisibleFieldID = previousFieldID;
343: if (this .binding.constant() == null)
344: this .binding.setConstant(Constant.NotAConstant);
345: }
346: }
347:
348: public void traverse(ASTVisitor visitor, MethodScope scope) {
349: if (visitor.visit(this , scope)) {
350: if (this .javadoc != null) {
351: this .javadoc.traverse(visitor, scope);
352: }
353: if (this .annotations != null) {
354: int annotationsLength = this .annotations.length;
355: for (int i = 0; i < annotationsLength; i++)
356: this.annotations[i].traverse(visitor, scope);
357: }
358: if (this.type != null) {
359: this.type.traverse(visitor, scope);
360: }
361: if (this.initialization != null)
362: this.initialization.traverse(visitor, scope);
363: }
364: visitor.endVisit(this, scope);
365: }
366: }
|