added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / FieldDeclaration.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12
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.*;
18
19 public class FieldDeclaration extends AbstractVariableDeclaration {
20         
21         public FieldBinding binding;
22         boolean hasBeenResolved = false;
23         public Javadoc javadoc;
24
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[]
31         // - part2 : b[] = X,
32
33         public int endPart1Position;
34         public int endPart2Position;
35
36         public FieldDeclaration() {
37                 // for subtypes or conversion
38         }
39
40         public FieldDeclaration(
41                 char[] name,
42                 int sourceStart,
43                 int sourceEnd) {
44
45                 this.name = name;
46
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;
52         }
53
54         public FlowInfo analyseCode(
55                 MethodScope initializationScope,
56                 FlowContext flowContext,
57                 FlowInfo flowInfo) {
58
59                 if (this.binding != null && this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
60                         if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
61                                 initializationScope.problemReporter().unusedPrivateField(this);
62                         }
63                 }
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,
74                                 this);
75                 }
76
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;
85                         }
86                         initializationScope.problemReporter().annotationFieldNeedConstantInitialization(this);
87                 }
88                 if (this.initialization != null) {
89                         flowInfo =
90                                 this.initialization
91                                         .analyseCode(initializationScope, flowContext, flowInfo)
92                                         .unconditionalInits();
93                         flowInfo.markAsDefinitelyAssigned(this.binding);
94                 }
95                 return flowInfo;
96         }
97
98         /**
99          * Code generation for a field declaration:
100          *         standard assignment to a field 
101          *
102          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
103          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
104          */
105         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
106
107                 if ((this.bits & IsReachableMASK) == 0) {
108                         return;
109                 }
110                 // do not generate initialization code if final and static (constant is then
111                 // recorded inside the field itself).
112                 int pc = codeStream.position;
113                 boolean isStatic;
114                 if (this.initialization != null
115                         && !((isStatic = this.binding.isStatic()) && this.binding.isConstantValue())) {
116                         // non-static field, need receiver
117                         if (!isStatic)
118                                 codeStream.aload_0();
119                         // generate initialization value
120                         this.initialization.generateCode(currentScope, codeStream, true);
121                         // store into field
122                         if (isStatic) {
123                                 codeStream.putstatic(this.binding);
124                         } else {
125                                 codeStream.putfield(this.binding);
126                         }
127                 }
128                 codeStream.recordPositionsFrom(pc, this.sourceStart);
129         }
130
131         /**
132          * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind()
133          */
134         public int getKind() {
135                 return this.type == null ? ENUM_CONSTANT : FIELD;
136         }
137         
138         public boolean isStatic() {
139
140                 if (this.binding != null)
141                         return this.binding.isStatic();
142                 return (this.modifiers & AccStatic) != 0;
143         }
144         
145         public void resolve(MethodScope initializationScope) {
146
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.
150
151                 //--------------------------------------------------------
152                 if (!this.hasBeenResolved && this.binding != null && this.binding.isValidBinding()) {
153
154                         this.hasBeenResolved = true;
155
156                         resolveAnnotations(initializationScope, this.annotations, this.binding);
157
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();
161                         
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
170                                         }
171                                 }
172                                 if (checkLocal) {
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);
182                                         }
183                                 }
184                         }
185                         
186                         if (this.type != null ) { // enum constants have no declared type
187                                 this.type.resolvedType = this.binding.type; // update binding for type reference
188                         }
189
190                         FieldBinding previousField = initializationScope.initializedField;
191                         int previousFieldID = initializationScope.lastVisibleFieldID;
192                         try {
193                                 initializationScope.initializedField = this.binding;
194                                 initializationScope.lastVisibleFieldID = this.binding.id;
195
196                                 // the resolution of the initialization hasn't been done
197                                 if (this.initialization == null) {
198                                         this.binding.setConstant(Constant.NotAConstant);
199                                 } else {
200                                         // break dead-lock cycles by forcing constant to NotAConstant
201                                         this.binding.setConstant(Constant.NotAConstant);
202                                         
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) {
207
208                                                 if ((initializationType = this.initialization.resolveTypeExpecting(initializationScope, fieldType)) != null) {
209                                                         ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationType;
210                                                         this.initialization.computeConversion(initializationScope, fieldType, initializationType);
211                                                 }
212                                         } else if ((initializationType = this.initialization.resolveType(initializationScope)) != null) {
213
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);
222                                                         }                                                                       
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);
230                                                 } else {
231                                                         initializationScope.problemReporter().typeMismatchError(initializationType, fieldType, this);
232                                                 }
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()));
235                                                 }
236                                         } else {
237                                                 this.binding.setConstant(NotAConstant);
238                                         }
239                                 }
240                                 // Resolve Javadoc comment if one is present
241                                 if (this.javadoc != null) {
242                                         /*
243                                         if (classScope != null) {
244                                                 this.javadoc.resolve(classScope);
245                                         }
246                                         */
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);
250                                 }
251                         } finally {
252                                 initializationScope.initializedField = previousField;
253                                 initializationScope.lastVisibleFieldID = previousFieldID;
254                                 if (this.binding.constant() == null)
255                                         this.binding.setConstant(Constant.NotAConstant);
256                         }
257                 }
258         }
259
260         public void traverse(ASTVisitor visitor, MethodScope scope) {
261
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);
267                         }
268                         if (this.type != null) {
269                                 this.type.traverse(visitor, scope);
270                         }
271                         if (this.initialization != null)
272                                 this.initialization.traverse(visitor, scope);
273                 }
274                 visitor.endVisit(this, scope);
275         }
276 }