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