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