first scanner /parser copied from the jdt java version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / Clinit.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.*;
15 import net.sourceforge.phpdt.internal.compiler.codegen.*;
16 import net.sourceforge.phpdt.internal.compiler.flow.*;
17 import net.sourceforge.phpdt.internal.compiler.lookup.*;
18 import net.sourceforge.phpdt.internal.compiler.parser.*;
19 import net.sourceforge.phpdt.internal.compiler.problem.*;
20
21 public class Clinit extends AbstractMethodDeclaration {
22         
23         public final static char[] ConstantPoolName = "<clinit>".toCharArray(); //$NON-NLS-1$
24
25         private FieldBinding assertionSyntheticFieldBinding = null;
26         private FieldBinding classLiteralSyntheticField = null;
27
28         public Clinit(CompilationResult compilationResult) {
29                 super(compilationResult);
30                 modifiers = 0;
31                 selector = ConstantPoolName;
32         }
33
34         public void analyseCode(
35                 ClassScope classScope,
36                 InitializationFlowContext staticInitializerFlowContext,
37                 FlowInfo flowInfo) {
38
39                 if (ignoreFurtherInvestigation)
40                         return;
41                 try {
42                         ExceptionHandlingFlowContext clinitContext =
43                                 new ExceptionHandlingFlowContext(
44                                         staticInitializerFlowContext.parent,
45                                         this,
46                                         NoExceptions,
47                                         scope,
48                                         FlowInfo.DeadEnd);
49
50                         // check for missing returning path
51                         needFreeReturn =
52                                 !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable());
53
54                         // check missing blank final field initializations
55                         flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
56                         FieldBinding[] fields = scope.enclosingSourceType().fields();
57                         for (int i = 0, count = fields.length; i < count; i++) {
58                                 FieldBinding field;
59                                 if ((field = fields[i]).isStatic()
60                                         && field.isFinal()
61                                         && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
62                                         scope.problemReporter().uninitializedBlankFinalField(
63                                                 field,
64                                                 scope.referenceType().declarationOf(field));
65                                         // can complain against the field decl, since only one <clinit>
66                                 }
67                         }
68                         // check static initializers thrown exceptions
69                         staticInitializerFlowContext.checkInitializerExceptions(
70                                 scope,
71                                 clinitContext,
72                                 flowInfo);
73                 } catch (AbortMethod e) {
74                         this.ignoreFurtherInvestigation = true;
75                 }
76         }
77
78         /**
79          * Bytecode generation for a <clinit> method
80          *
81          * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
82          * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
83          */
84         public void generateCode(ClassScope classScope, ClassFile classFile) {
85
86                 int clinitOffset = 0;
87                 if (ignoreFurtherInvestigation) {
88                         // should never have to add any <clinit> problem method
89                         return;
90                 }
91                 try {
92                         clinitOffset = classFile.contentsOffset;
93                         this.generateCode(classScope, classFile, clinitOffset);
94                 } catch (AbortMethod e) {
95                         // should never occur
96                         // the clinit referenceContext is the type declaration
97                         // All clinit problems will be reported against the type: AbortType instead of AbortMethod
98                         // reset the contentsOffset to the value before generating the clinit code
99                         // decrement the number of method info as well.
100                         // This is done in the addProblemMethod and addProblemConstructor for other
101                         // cases.
102                         if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
103                                 // a branch target required a goto_w, restart code gen in wide mode.
104                                 try {
105                                         if (statements != null) {
106                                                 for (int i = 0, max = statements.length; i < max; i++)
107                                                         statements[i].resetStateForCodeGeneration();
108                                         }
109                                         classFile.contentsOffset = clinitOffset;
110                                         classFile.methodCount--;
111                                         classFile.codeStream.wideMode = true; // request wide mode 
112                                         this.generateCode(classScope, classFile, clinitOffset);
113                                         // restart method generation
114                                 } catch (AbortMethod e2) {
115                                         classFile.contentsOffset = clinitOffset;
116                                         classFile.methodCount--;
117                                 }
118                         } else {
119                                 // produce a problem method accounting for this fatal error
120                                 classFile.contentsOffset = clinitOffset;
121                                 classFile.methodCount--;
122                         }
123                 }
124         }
125
126         /**
127          * Bytecode generation for a <clinit> method
128          *
129          * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
130          * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
131          */
132         private void generateCode(
133                 ClassScope classScope,
134                 ClassFile classFile,
135                 int clinitOffset) {
136
137                 ConstantPool constantPool = classFile.constantPool;
138                 int constantPoolOffset = constantPool.currentOffset;
139                 int constantPoolIndex = constantPool.currentIndex;
140                 classFile.generateMethodInfoHeaderForClinit();
141                 int codeAttributeOffset = classFile.contentsOffset;
142                 classFile.generateCodeAttributeHeader();
143                 CodeStream codeStream = classFile.codeStream;
144                 this.resolve(classScope);
145
146                 codeStream.reset(this, classFile);
147                 TypeDeclaration declaringType = classScope.referenceContext;
148
149                 // initialize local positions - including initializer scope.
150                 scope.computeLocalVariablePositions(0, codeStream); // should not be necessary
151                 MethodScope staticInitializerScope = declaringType.staticInitializerScope;
152                 staticInitializerScope.computeLocalVariablePositions(0, codeStream);
153                 // offset by the argument size
154
155                 // 1.4 feature
156                 // This has to be done before any other initialization
157                 if (this.assertionSyntheticFieldBinding != null) {
158                         // generate code related to the activation of assertion for this class
159                         codeStream.generateClassLiteralAccessForType(
160                                 classScope.enclosingSourceType(),
161                                 classLiteralSyntheticField);
162                         codeStream.invokeJavaLangClassDesiredAssertionStatus();
163                         Label falseLabel = new Label(codeStream);
164                         codeStream.ifne(falseLabel);
165                         codeStream.iconst_1();
166                         Label jumpLabel = new Label(codeStream);
167                         codeStream.goto_(jumpLabel);
168                         falseLabel.place();
169                         codeStream.iconst_0();
170                         jumpLabel.place();
171                         codeStream.putstatic(this.assertionSyntheticFieldBinding);
172                 }
173                 // generate initializers
174                 if (declaringType.fields != null) {
175                         for (int i = 0, max = declaringType.fields.length; i < max; i++) {
176                                 FieldDeclaration fieldDecl;
177                                 if ((fieldDecl = declaringType.fields[i]).isStatic()) {
178                                         fieldDecl.generateCode(staticInitializerScope, codeStream);
179                                 }
180                         }
181                 }
182                 if (codeStream.position == 0) {
183                         // do not need to output a Clinit if no bytecodes
184                         // so we reset the offset inside the byte array contents.
185                         classFile.contentsOffset = clinitOffset;
186                         // like we don't addd a method we need to undo the increment on the method count
187                         classFile.methodCount--;
188                         // reset the constant pool to its state before the clinit
189                         constantPool.resetForClinit(constantPoolIndex, constantPoolOffset);
190                 } else {
191                         if (needFreeReturn) {
192                                 int oldPosition = codeStream.position;
193                                 codeStream.return_();
194                                 codeStream.updateLocalVariablesAttribute(oldPosition);
195                         }
196                         // Record the end of the clinit: point to the declaration of the class
197                         codeStream.recordPositionsFrom(0, declaringType.sourceStart);
198                         classFile.completeCodeAttributeForClinit(codeAttributeOffset);
199                 }
200         }
201
202         public boolean isClinit() {
203
204                 return true;
205         }
206
207         public boolean isInitializationMethod() {
208
209                 return true;
210         }
211
212         public boolean isStatic() {
213
214                 return true;
215         }
216
217         public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
218                 //the clinit is filled by hand .... 
219         }
220
221         public void resolve(ClassScope scope) {
222
223                 this.scope = new MethodScope(scope, scope.referenceContext, true);
224         }
225
226         public String toString(int tab) {
227
228                 String s = ""; //$NON-NLS-1$
229                 s = s + tabString(tab);
230                 s = s + "<clinit>()"; //$NON-NLS-1$
231                 s = s + toStringStatements(tab + 1);
232                 return s;
233         }
234
235         public void traverse(
236                 IAbstractSyntaxTreeVisitor visitor,
237                 ClassScope classScope) {
238
239                 visitor.visit(this, classScope);
240                 visitor.endVisit(this, classScope);
241         }
242
243         // 1.4 feature
244         public void addSupportForAssertion(FieldBinding assertionSyntheticFieldBinding) {
245
246                 this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding;
247
248                 // we need to add the field right now, because the field infos are generated before the methods
249                 SourceTypeBinding sourceType =
250                         this.scope.outerMostMethodScope().enclosingSourceType();
251                 this.classLiteralSyntheticField =
252                         sourceType.addSyntheticField(sourceType, scope);
253         }
254
255 }