Fixing some bugs and making the plug-in compatible with Java 1.4
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / CompilationUnitDeclaration.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.internal.compiler.ast;
12
13 import java.util.ArrayList;
14
15 import net.sourceforge.phpdt.core.compiler.CharOperation;
16 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
17 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
18 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
19 import net.sourceforge.phpdt.internal.compiler.lookup.CompilationUnitScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
21 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilationUnit;
22 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
23 import net.sourceforge.phpdt.internal.compiler.problem.AbortType;
24 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
25 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
26
27 public class CompilationUnitDeclaration extends ASTNode implements
28                 ProblemSeverities, ReferenceContext {
29
30         public ImportReference currentPackage;
31
32         public ImportReference[] imports;
33
34         // public TypeDeclaration[] types;
35         public ArrayList types;
36
37         // public char[][] name;
38         public int[][] comments;
39
40         public boolean ignoreFurtherInvestigation = false; // once pointless to
41                                                                                                                 // investigate due to
42                                                                                                                 // errors
43
44         public boolean ignoreMethodBodies = false;
45
46         public CompilationUnitScope scope;
47
48         public ProblemReporter problemReporter;
49
50         public CompilationResult compilationResult;
51
52         private LocalTypeBinding[] localTypes;
53
54         int localTypeCount = 0;
55
56         public boolean isPropagatingInnerClassEmulation;
57
58         public CompilationUnitDeclaration(ProblemReporter problemReporter,
59                         CompilationResult compilationResult, int sourceLength) {
60
61                 this.problemReporter = problemReporter;
62                 this.compilationResult = compilationResult;
63                 this.types = new ArrayList();
64                 // by definition of a compilation unit....
65                 sourceStart = 0;
66                 sourceEnd = sourceLength - 1;
67         }
68
69         /*
70          * We cause the compilation task to abort to a given extent.
71          */
72         public void abort(int abortLevel) {
73
74                 switch (abortLevel) {
75                 case AbortType:
76                         throw new AbortType(compilationResult);
77                 case AbortMethod:
78                         throw new AbortMethod(compilationResult);
79                 default:
80                         throw new AbortCompilationUnit(compilationResult);
81                 }
82         }
83
84         /*
85          * Dispatch code analysis AND request saturation of inner emulation
86          */
87         public void analyseCode() {
88
89                 if (ignoreFurtherInvestigation)
90                         return;
91                 try {
92                         if (types != null) {
93                                 for (int i = 0, count = types.size(); i < count; i++) {
94                                         if (types.get(i) instanceof TypeDeclaration)
95                                                 ((TypeDeclaration) types.get(i)).analyseCode(scope);
96                                 }
97                         }
98                         // request inner emulation propagation
99                         propagateInnerEmulationForAllLocalTypes();
100                 } catch (AbortCompilationUnit e) {
101                         this.ignoreFurtherInvestigation = true;
102                         return;
103                 }
104         }
105
106         /*
107          * When unit result is about to be accepted, removed back pointers to
108          * compiler structures.
109          */
110         public void cleanUp() {
111                 if (this.types != null) {
112                         for (int i = 0, max = this.types.size(); i < max; i++) {
113                                 if (this.types.get(i) instanceof TypeDeclaration) {
114                                         cleanUp((TypeDeclaration) this.types.get(i));
115                                 }
116                         }
117                         for (int i = 0, max = this.localTypeCount; i < max; i++) {
118                                 // null out the type's scope backpointers
119                                 localTypes[i].scope = null; // local members are already in the
120                                                                                         // list
121                         }
122                 }
123                 // ClassFile[] classFiles = compilationResult.getClassFiles();
124                 // for (int i = 0, max = classFiles.length; i < max; i++) {
125                 // // clear the classFile back pointer to the bindings
126                 // ClassFile classFile = classFiles[i];
127                 // // null out the classfile backpointer to a type binding
128                 // classFile.referenceBinding = null;
129                 // classFile.codeStream = null; // codeStream holds onto ast and scopes
130                 // classFile.innerClassesBindings = null;
131                 // }
132         }
133
134         private void cleanUp(TypeDeclaration type) {
135                 if (type.memberTypes != null) {
136                         for (int i = 0, max = type.memberTypes.length; i < max; i++) {
137                                 cleanUp(type.memberTypes[i]);
138                         }
139                 }
140                 if (type.binding != null) {
141                         // null out the type's scope backpointers
142                         type.binding.scope = null;
143                 }
144         }
145
146         // public void checkUnusedImports() {
147         //
148         // if (this.scope.imports != null) {
149         // for (int i = 0, max = this.scope.imports.length; i < max; i++) {
150         // ImportBinding importBinding = this.scope.imports[i];
151         // ImportReference importReference = importBinding.reference;
152         // if (importReference != null && !importReference.used) {
153         // scope.problemReporter().unusedImport(importReference);
154         // }
155         // }
156         // }
157         // }
158
159         public CompilationResult compilationResult() {
160                 return compilationResult;
161         }
162
163         /*
164          * Finds the matching type amoung this compilation unit types. Returns null
165          * if no type with this name is found. The type name is a compound name eg.
166          * if we're looking for X.A.B then a type name would be {X, A, B}
167          */
168         public TypeDeclaration declarationOfType(char[][] typeName) {
169
170                 for (int i = 0; i < this.types.size(); i++) {
171                         if (this.types.get(i) instanceof TypeDeclaration) {
172                                 TypeDeclaration typeDecl = ((TypeDeclaration) this.types.get(i))
173                                                 .declarationOfType(typeName);
174                                 if (typeDecl != null) {
175                                         return typeDecl;
176                                 }
177                         }
178                 }
179                 return null;
180         }
181
182         /**
183          * Bytecode generation
184          */
185         // public void generateCode() {
186         //
187         // if (ignoreFurtherInvestigation) {
188         // if (types != null) {
189         // for (int i = 0, count = types.length; i < count; i++) {
190         // types[i].ignoreFurtherInvestigation = true;
191         // // propagate the flag to request problem type creation
192         // types[i].generateCode(scope);
193         // }
194         // }
195         // return;
196         // }
197         // try {
198         // if (types != null) {
199         // for (int i = 0, count = types.length; i < count; i++)
200         // types[i].generateCode(scope);
201         // }
202         // } catch (AbortCompilationUnit e) {
203         // }
204         // }
205         public char[] getFileName() {
206
207                 return compilationResult.getFileName();
208         }
209
210         public char[] getMainTypeName() {
211
212                 if (compilationResult.compilationUnit == null) {
213                         char[] fileName = compilationResult.getFileName();
214
215                         int start = CharOperation.lastIndexOf('/', fileName) + 1;
216                         if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName))
217                                 start = CharOperation.lastIndexOf('\\', fileName) + 1;
218
219                         int end = CharOperation.lastIndexOf('.', fileName);
220                         if (end == -1)
221                                 end = fileName.length;
222
223                         return CharOperation.subarray(fileName, start, end);
224                 } else {
225                         return compilationResult.compilationUnit.getMainTypeName();
226                 }
227         }
228
229         public boolean isEmpty() {
230
231                 return (currentPackage == null) && (imports == null) && (types == null);
232         }
233
234         public boolean hasErrors() {
235                 return this.ignoreFurtherInvestigation;
236         }
237
238         public StringBuffer print(int indent, StringBuffer output) {
239
240                 if (currentPackage != null) {
241                         printIndent(indent, output).append("package "); //$NON-NLS-1$
242                         currentPackage.print(0, output, false).append(";\n"); //$NON-NLS-1$
243                 }
244                 if (imports != null)
245                         for (int i = 0; i < imports.length; i++) {
246                                 printIndent(indent, output).append("import "); //$NON-NLS-1$
247                                 imports[i].print(0, output).append(";\n"); //$NON-NLS-1$ 
248                         }
249
250                 if (types != null) {
251                         for (int i = 0; i < types.size(); i++) {
252                                 ((ASTNode) types.get(i)).print(indent, output).append("\n"); //$NON-NLS-1$
253                         }
254                 }
255                 return output;
256         }
257
258         /*
259          * Force inner local types to update their innerclass emulation
260          */
261         public void propagateInnerEmulationForAllLocalTypes() {
262
263                 isPropagatingInnerClassEmulation = true;
264                 for (int i = 0, max = this.localTypeCount; i < max; i++) {
265
266                         LocalTypeBinding localType = localTypes[i];
267                         // only propagate for reachable local types
268                         if ((localType.scope.referenceType().bits & IsReachableMASK) != 0) {
269                                 localType.updateInnerEmulationDependents();
270                         }
271                 }
272         }
273
274         /*
275          * Keep track of all local types, so as to update their innerclass emulation
276          * later on.
277          */
278         public void record(LocalTypeBinding localType) {
279
280                 if (this.localTypeCount == 0) {
281                         this.localTypes = new LocalTypeBinding[5];
282                 } else if (this.localTypeCount == this.localTypes.length) {
283                         System
284                                         .arraycopy(
285                                                         this.localTypes,
286                                                         0,
287                                                         (this.localTypes = new LocalTypeBinding[this.localTypeCount * 2]),
288                                                         0, this.localTypeCount);
289                 }
290                 this.localTypes[this.localTypeCount++] = localType;
291         }
292
293         public void resolve() {
294
295                 try {
296                         if (types != null) {
297                                 for (int i = 0, count = types.size(); i < count; i++) {
298                                         if (types.get(i) instanceof TypeDeclaration) {
299                                                 ((TypeDeclaration) types.get(i)).resolve(scope);
300                                         }
301                                 }
302                         }
303                         // if (!this.compilationResult.hasSyntaxError())
304                         // checkUnusedImports();
305                 } catch (AbortCompilationUnit e) {
306                         this.ignoreFurtherInvestigation = true;
307                         return;
308                 }
309         }
310
311         public void tagAsHavingErrors() {
312                 ignoreFurtherInvestigation = true;
313         }
314
315         public String toString(int tab) {
316
317                 String s = ""; //$NON-NLS-1$
318                 if (currentPackage != null)
319                         s = tabString(tab)
320                                         + "package " + currentPackage.toString(0, false) + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$
321
322                 if (imports != null)
323                         for (int i = 0; i < imports.length; i++) {
324                                 s += tabString(tab)
325                                                 + "include " + imports[i].toString() + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$
326                         }
327                 ;
328
329                 if (types != null)
330                         for (int i = 0; i < types.size(); i++) {
331                                 s += ((ASTNode) types.get(i)).toString(tab) + "\n"; //$NON-NLS-1$
332                         }
333                 return s;
334         }
335
336         public void traverse(ASTVisitor visitor, CompilationUnitScope scope) {
337
338                 if (ignoreFurtherInvestigation)
339                         return;
340                 try {
341                         if (visitor.visit(this, scope)) {
342                                 if (currentPackage != null) {
343                                         currentPackage.traverse(visitor, scope);
344                                 }
345                                 if (imports != null) {
346                                         int importLength = imports.length;
347                                         for (int i = 0; i < importLength; i++) {
348                                                 imports[i].traverse(visitor, scope);
349                                         }
350                                 }
351                                 if (types != null) {
352                                         int typesLength = types.size();
353                                         for (int i = 0; i < typesLength; i++) {
354                                                 if (types.get(i) instanceof TypeDeclaration) {
355                                                         ((TypeDeclaration) types.get(i)).traverse(visitor,
356                                                                         scope);
357                                                 }
358                                         }
359                                 }
360                         }
361                         visitor.endVisit(this, scope);
362                 } catch (AbortCompilationUnit e) {
363                 }
364         }
365 }