It's now possible to assign a value to a variable
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / CompilationUnitDeclaration.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.*;
14 import net.sourceforge.phpdt.internal.compiler.impl.*;
15 import net.sourceforge.phpdt.internal.compiler.lookup.*;
16 import net.sourceforge.phpdt.internal.compiler.problem.*;
17 import net.sourceforge.phpdt.internal.compiler.util.*;
18
19 public class CompilationUnitDeclaration
20         extends AstNode
21         implements ProblemSeverities, ReferenceContext {
22                 
23         public ImportReference currentPackage;
24         public ImportReference[] imports;
25         public TypeDeclaration[] types;
26         //public char[][] name;
27
28         public boolean ignoreFurtherInvestigation = false;      // once pointless to investigate due to errors
29         public boolean ignoreMethodBodies = false;
30         public CompilationUnitScope scope;
31         public ProblemReporter problemReporter;
32         public CompilationResult compilationResult;
33
34         private LocalTypeBinding[] allLocalTypes;
35         public boolean isPropagatingInnerClassEmulation;
36
37         public CompilationUnitDeclaration(
38                 ProblemReporter problemReporter,
39                 CompilationResult compilationResult,
40                 int sourceLength) {
41
42                 this.problemReporter = problemReporter;
43                 this.compilationResult = compilationResult;
44
45                 //by definition of a compilation unit....
46                 sourceStart = 0;
47                 sourceEnd = sourceLength - 1;
48
49         }
50
51         /*
52          *      We cause the compilation task to abort to a given extent.
53          */
54         public void abort(int abortLevel) {
55
56                 switch (abortLevel) {
57                         case AbortType :
58                                 throw new AbortType(compilationResult);
59                         case AbortMethod :
60                                 throw new AbortMethod(compilationResult);
61                         default :
62                                 throw new AbortCompilationUnit(compilationResult);
63                 }
64         }
65
66         /*
67          * Dispatch code analysis AND request saturation of inner emulation
68          */
69         public void analyseCode() {
70
71                 if (ignoreFurtherInvestigation)
72                         return;
73                 try {
74                         if (types != null) {
75                                 for (int i = 0, count = types.length; i < count; i++) {
76                                         types[i].analyseCode(scope);
77                                 }
78                         }
79                         // request inner emulation propagation
80                         propagateInnerEmulationForAllLocalTypes();
81                 } catch (AbortCompilationUnit e) {
82                         this.ignoreFurtherInvestigation = true;
83                         return;
84                 }
85         }
86
87         /*
88          * When unit result is about to be accepted, removed back pointers
89          * to compiler structures.
90          */
91         public void cleanUp() {
92
93                 ClassFile[] classFiles = compilationResult.getClassFiles();
94                 for (int i = 0, max = classFiles.length; i < max; i++) {
95                         // clear the classFile back pointer to the bindings
96                         ClassFile classFile = classFiles[i];
97                         // null out the type's scope backpointers
98                          ((SourceTypeBinding) classFile.referenceBinding).scope = null;
99                         // null out the classfile backpointer to a type binding
100                         classFile.referenceBinding = null;
101                         classFile.codeStream = null; // codeStream holds onto ast and scopes
102                         classFile.innerClassesBindings = null;
103                 }
104         }
105
106         public void checkUnusedImports(){
107                 
108                 if (this.scope.imports != null){
109                         for (int i = 0, max = this.scope.imports.length; i < max; i++){
110                                 ImportBinding importBinding = this.scope.imports[i];
111                                 ImportReference importReference = importBinding.reference;
112                                 if (importReference != null && !importReference.used){
113                                         scope.problemReporter().unusedImport(importReference);
114                                 }
115                         }
116                 }
117         }
118         
119         public CompilationResult compilationResult() {
120                 return compilationResult;
121         }
122         
123         /*
124          * Finds the matching type amoung this compilation unit types.
125          * Returns null if no type with this name is found.
126          * The type name is a compound name
127          * eg. if we're looking for X.A.B then a type name would be {X, A, B}
128          */
129         public TypeDeclaration declarationOfType(char[][] typeName) {
130
131                 for (int i = 0; i < this.types.length; i++) {
132                         TypeDeclaration typeDecl = this.types[i].declarationOfType(typeName);
133                         if (typeDecl != null) {
134                                 return typeDecl;
135                         }
136                 }
137                 return null;
138         }
139
140         /**
141          * Bytecode generation
142          */
143         public void generateCode() {
144
145                 if (ignoreFurtherInvestigation) {
146                         if (types != null) {
147                                 for (int i = 0, count = types.length; i < count; i++) {
148                                         types[i].ignoreFurtherInvestigation = true;
149                                         // propagate the flag to request problem type creation
150                                         types[i].generateCode(scope);
151                                 }
152                         }
153                         return;
154                 }
155                 try {
156                         if (types != null) {
157                                 for (int i = 0, count = types.length; i < count; i++)
158                                         types[i].generateCode(scope);
159                         }
160                 } catch (AbortCompilationUnit e) {
161                 }
162         }
163
164         public char[] getFileName() {
165
166                 return compilationResult.getFileName();
167         }
168
169         public char[] getMainTypeName() {
170
171                 if (compilationResult.compilationUnit == null) {
172                         char[] fileName = compilationResult.getFileName();
173
174                         int start = CharOperation.lastIndexOf('/', fileName) + 1;
175                         if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName))
176                                 start = CharOperation.lastIndexOf('\\', fileName) + 1;
177
178                         int end = CharOperation.lastIndexOf('.', fileName);
179                         if (end == -1)
180                                 end = fileName.length;
181
182                         return CharOperation.subarray(fileName, start, end);
183                 } else {
184                         return compilationResult.compilationUnit.getMainTypeName();
185                 }
186         }
187
188         public boolean isEmpty() {
189
190                 return (currentPackage == null) && (imports == null) && (types == null);
191         }
192
193         public boolean hasErrors() {
194                 return this.ignoreFurtherInvestigation;
195         }
196
197         /*
198          * Force inner local types to update their innerclass emulation
199          */
200         public void propagateInnerEmulationForAllLocalTypes() {
201
202                 isPropagatingInnerClassEmulation = true;
203                 if (allLocalTypes != null) {
204                         for (int i = 0, max = allLocalTypes.length; i < max; i++) {
205                                 allLocalTypes[i].updateInnerEmulationDependents();
206                         }
207                 }
208         }
209
210         /*
211          * Keep track of all local types, so as to update their innerclass
212          * emulation later on.
213          */
214         public void record(LocalTypeBinding localType) {
215
216                 if (allLocalTypes == null) {
217                         allLocalTypes = new LocalTypeBinding[] { localType };
218                 } else {
219                         int length = allLocalTypes.length;
220                         System.arraycopy(
221                                 allLocalTypes,
222                                 0,
223                                 (allLocalTypes = new LocalTypeBinding[length + 1]),
224                                 0,
225                                 length);
226                         allLocalTypes[length] = localType;
227                 }
228         }
229
230         public void resolve() {
231
232                 try {
233                         if (types != null) {
234                                 for (int i = 0, count = types.length; i < count; i++) {
235                                         types[i].resolve(scope);
236                                 }
237                         }
238                         checkUnusedImports();
239                 } catch (AbortCompilationUnit e) {
240                         this.ignoreFurtherInvestigation = true;
241                         return;
242                 }
243         }
244
245         public void tagAsHavingErrors() {
246                 ignoreFurtherInvestigation = true;
247         }
248
249         public String toString(int tab) {
250
251                 String s = ""; //$NON-NLS-1$
252                 if (currentPackage != null)
253                         s = tabString(tab) + "package " + currentPackage.toString(0, false) + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$
254
255                 if (imports != null)
256                         for (int i = 0; i < imports.length; i++) {
257                                 s += tabString(tab) + "import " + imports[i].toString() + ";\n"; //$NON-NLS-1$ //$NON-NLS-2$
258                         };
259
260                 if (types != null)
261                         for (int i = 0; i < types.length; i++) {
262                                 s += types[i].toString(tab) + "\n"; //$NON-NLS-1$
263                         }
264                 return s;
265         }
266
267         public void traverse(
268                 IAbstractSyntaxTreeVisitor visitor,
269                 CompilationUnitScope scope) {
270
271                 if (ignoreFurtherInvestigation)
272                         return;
273                 try {
274                         if (visitor.visit(this, scope)) {
275                                 if (imports != null) {
276                                         int importLength = imports.length;
277                                         for (int i = 0; i < importLength; i++)
278                                                 imports[i].traverse(visitor, scope);
279                                 }
280                                 if (types != null) {
281                                         int typesLength = types.length;
282                                         for (int i = 0; i < typesLength; i++)
283                                                 types[i].traverse(visitor, scope);
284                                 }
285                         }
286                         visitor.endVisit(this, scope);
287                 } catch (AbortCompilationUnit e) {
288                 }
289         }
290 }