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