KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > CompilationUnitDeclaration


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import java.util.Arrays JavaDoc;
14 import java.util.Comparator JavaDoc;
15
16 import org.eclipse.jdt.core.compiler.CategorizedProblem;
17 import org.eclipse.jdt.core.compiler.CharOperation;
18 import org.eclipse.jdt.internal.compiler.ASTVisitor;
19 import org.eclipse.jdt.internal.compiler.ClassFile;
20 import org.eclipse.jdt.internal.compiler.CompilationResult;
21 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
22 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
23 import org.eclipse.jdt.internal.compiler.lookup.ImportBinding;
24 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
25 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
26 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
27 import org.eclipse.jdt.internal.compiler.parser.NLSTag;
28 import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit;
29 import org.eclipse.jdt.internal.compiler.problem.AbortMethod;
30 import org.eclipse.jdt.internal.compiler.problem.AbortType;
31 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
32 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
33
34 public class CompilationUnitDeclaration
35     extends ASTNode
36     implements ProblemSeverities, ReferenceContext {
37
38     private static final Comparator JavaDoc STRING_LITERAL_COMPARATOR = new Comparator JavaDoc() {
39         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
40             StringLiteral literal1 = (StringLiteral) o1;
41             StringLiteral literal2 = (StringLiteral) o2;
42             return literal1.sourceStart - literal2.sourceStart;
43         }
44     };
45     private static final int STRING_LITERALS_INCREMENT = 10;
46
47     public ImportReference currentPackage;
48     public ImportReference[] imports;
49     public TypeDeclaration[] types;
50     public int[][] comments;
51
52     public boolean ignoreFurtherInvestigation = false; // once pointless to investigate due to errors
53
public boolean ignoreMethodBodies = false;
54     public CompilationUnitScope scope;
55     public ProblemReporter problemReporter;
56     public CompilationResult compilationResult;
57
58     public LocalTypeBinding[] localTypes;
59     public int localTypeCount = 0;
60
61     public boolean isPropagatingInnerClassEmulation;
62
63     public Javadoc javadoc; // 1.5 addition for package-info.java
64

65     public NLSTag[] nlsTags;
66     private StringLiteral[] stringLiterals;
67     private int stringLiteralsPtr;
68
69     public CompilationUnitDeclaration(
70         ProblemReporter problemReporter,
71         CompilationResult compilationResult,
72         int sourceLength) {
73
74         this.problemReporter = problemReporter;
75         this.compilationResult = compilationResult;
76
77         //by definition of a compilation unit....
78
sourceStart = 0;
79         sourceEnd = sourceLength - 1;
80     }
81
82     /*
83      * We cause the compilation task to abort to a given extent.
84      */

85     public void abort(int abortLevel, CategorizedProblem problem) {
86
87         switch (abortLevel) {
88             case AbortType :
89                 throw new AbortType(this.compilationResult, problem);
90             case AbortMethod :
91                 throw new AbortMethod(this.compilationResult, problem);
92             default :
93                 throw new AbortCompilationUnit(this.compilationResult, problem);
94         }
95     }
96
97     /*
98      * Dispatch code analysis AND request saturation of inner emulation
99      */

100     public void analyseCode() {
101
102         if (ignoreFurtherInvestigation)
103             return;
104         try {
105             if (types != null) {
106                 for (int i = 0, count = types.length; i < count; i++) {
107                     types[i].analyseCode(scope);
108                 }
109             }
110             // request inner emulation propagation
111
propagateInnerEmulationForAllLocalTypes();
112         } catch (AbortCompilationUnit e) {
113             this.ignoreFurtherInvestigation = true;
114             return;
115         }
116     }
117
118     /*
119      * When unit result is about to be accepted, removed back pointers
120      * to compiler structures.
121      */

122     public void cleanUp() {
123         if (this.types != null) {
124             for (int i = 0, max = this.types.length; i < max; i++) {
125                 cleanUp(this.types[i]);
126             }
127             for (int i = 0, max = this.localTypeCount; i < max; i++) {
128                 LocalTypeBinding localType = localTypes[i];
129                 // null out the type's scope backpointers
130
localType.scope = null; // local members are already in the list
131
localType.enclosingCase = null;
132             }
133         }
134
135         compilationResult.recoveryScannerData = null; // recovery is already done
136

137         ClassFile[] classFiles = compilationResult.getClassFiles();
138         for (int i = 0, max = classFiles.length; i < max; i++) {
139             // clear the classFile back pointer to the bindings
140
ClassFile classFile = classFiles[i];
141             // null out the classfile backpointer to a type binding
142
classFile.referenceBinding = null;
143             classFile.innerClassesBindings = null;
144         }
145     }
146     private void cleanUp(TypeDeclaration type) {
147         if (type.memberTypes != null) {
148             for (int i = 0, max = type.memberTypes.length; i < max; i++){
149                 cleanUp(type.memberTypes[i]);
150             }
151         }
152         if (type.binding != null && type.binding.isAnnotationType())
153             compilationResult.hasAnnotations = true;
154         if (type.binding != null) {
155             // null out the type's scope backpointers
156
type.binding.scope = null;
157         }
158     }
159
160     public void checkUnusedImports(){
161
162         if (this.scope.imports != null){
163             for (int i = 0, max = this.scope.imports.length; i < max; i++){
164                 ImportBinding importBinding = this.scope.imports[i];
165                 ImportReference importReference = importBinding.reference;
166                 if (importReference != null && ((importReference.bits & ASTNode.Used) == 0)){
167                     scope.problemReporter().unusedImport(importReference);
168                 }
169             }
170         }
171     }
172
173     public CompilationResult compilationResult() {
174         return this.compilationResult;
175     }
176
177     /*
178      * Finds the matching type amoung this compilation unit types.
179      * Returns null if no type with this name is found.
180      * The type name is a compound name
181      * eg. if we're looking for X.A.B then a type name would be {X, A, B}
182      */

183     public TypeDeclaration declarationOfType(char[][] typeName) {
184
185         for (int i = 0; i < this.types.length; i++) {
186             TypeDeclaration typeDecl = this.types[i].declarationOfType(typeName);
187             if (typeDecl != null) {
188                 return typeDecl;
189             }
190         }
191         return null;
192     }
193
194     /**
195      * Bytecode generation
196      */

197     public void generateCode() {
198
199         if (ignoreFurtherInvestigation) {
200             if (types != null) {
201                 for (int i = 0, count = types.length; i < count; i++) {
202                     types[i].ignoreFurtherInvestigation = true;
203                     // propagate the flag to request problem type creation
204
types[i].generateCode(scope);
205                 }
206             }
207             return;
208         }
209         if (this.isPackageInfo() && this.types != null && this.currentPackage!= null && this.currentPackage.annotations != null) {
210             types[0].annotations = this.currentPackage.annotations;
211         }
212         try {
213             if (types != null) {
214                 for (int i = 0, count = types.length; i < count; i++)
215                     types[i].generateCode(scope);
216             }
217         } catch (AbortCompilationUnit e) {
218             // ignore
219
}
220     }
221
222     public char[] getFileName() {
223
224         return compilationResult.getFileName();
225     }
226
227     public char[] getMainTypeName() {
228
229         if (compilationResult.compilationUnit == null) {
230             char[] fileName = compilationResult.getFileName();
231
232             int start = CharOperation.lastIndexOf('/', fileName) + 1;
233             if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName))
234                 start = CharOperation.lastIndexOf('\\', fileName) + 1;
235
236             int end = CharOperation.lastIndexOf('.', fileName);
237             if (end == -1)
238                 end = fileName.length;
239
240             return CharOperation.subarray(fileName, start, end);
241         } else {
242             return compilationResult.compilationUnit.getMainTypeName();
243         }
244     }
245
246     public boolean isEmpty() {
247
248         return (currentPackage == null) && (imports == null) && (types == null);
249     }
250
251     public boolean isPackageInfo() {
252         return CharOperation.equals(this.getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME);
253     }
254
255     public boolean hasErrors() {
256         return this.ignoreFurtherInvestigation;
257     }
258
259     public StringBuffer JavaDoc print(int indent, StringBuffer JavaDoc output) {
260
261         if (currentPackage != null) {
262             printIndent(indent, output).append("package "); //$NON-NLS-1$
263
currentPackage.print(0, output, false).append(";\n"); //$NON-NLS-1$
264
}
265         if (imports != null)
266             for (int i = 0; i < imports.length; i++) {
267                 printIndent(indent, output).append("import "); //$NON-NLS-1$
268
ImportReference currentImport = imports[i];
269                 if (currentImport.isStatic()) {
270                     output.append("static "); //$NON-NLS-1$
271
}
272                 currentImport.print(0, output).append(";\n"); //$NON-NLS-1$
273
}
274
275         if (types != null) {
276             for (int i = 0; i < types.length; i++) {
277                 types[i].print(indent, output).append("\n"); //$NON-NLS-1$
278
}
279         }
280         return output;
281     }
282
283     /*
284      * Force inner local types to update their innerclass emulation
285      */

286     public void propagateInnerEmulationForAllLocalTypes() {
287
288         isPropagatingInnerClassEmulation = true;
289         for (int i = 0, max = this.localTypeCount; i < max; i++) {
290
291             LocalTypeBinding localType = localTypes[i];
292             // only propagate for reachable local types
293
if ((localType.scope.referenceType().bits & IsReachable) != 0) {
294                 localType.updateInnerEmulationDependents();
295             }
296         }
297     }
298
299     public void recordStringLiteral(StringLiteral literal) {
300         if (this.stringLiterals == null) {
301             this.stringLiterals = new StringLiteral[STRING_LITERALS_INCREMENT];
302             this.stringLiteralsPtr = 0;
303         } else {
304             int stackLength = this.stringLiterals.length;
305             if (this.stringLiteralsPtr == stackLength) {
306                 System.arraycopy(
307                     this.stringLiterals,
308                     0,
309                     this.stringLiterals = new StringLiteral[stackLength + STRING_LITERALS_INCREMENT],
310                     0,
311                     stackLength);
312             }
313         }
314         this.stringLiterals[this.stringLiteralsPtr++] = literal;
315     }
316
317     /*
318      * Keep track of all local types, so as to update their innerclass
319      * emulation later on.
320      */

321     public void record(LocalTypeBinding localType) {
322
323         if (this.localTypeCount == 0) {
324             this.localTypes = new LocalTypeBinding[5];
325         } else if (this.localTypeCount == this.localTypes.length) {
326             System.arraycopy(this.localTypes, 0, (this.localTypes = new LocalTypeBinding[this.localTypeCount * 2]), 0, this.localTypeCount);
327         }
328         this.localTypes[this.localTypeCount++] = localType;
329     }
330
331     public void resolve() {
332         int startingTypeIndex = 0;
333         boolean isPackageInfo = isPackageInfo();
334         if (this.types != null && isPackageInfo) {
335             // resolve synthetic type declaration
336
final TypeDeclaration syntheticTypeDeclaration = types[0];
337             // set empty javadoc to avoid missing warning (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=95286)
338
if (syntheticTypeDeclaration.javadoc == null) {
339                 syntheticTypeDeclaration.javadoc = new Javadoc(syntheticTypeDeclaration.declarationSourceStart, syntheticTypeDeclaration.declarationSourceStart);
340             }
341             syntheticTypeDeclaration.resolve(this.scope);
342             // resolve annotations if any
343
if (this.currentPackage!= null && this.currentPackage.annotations != null) {
344                 resolveAnnotations(syntheticTypeDeclaration.staticInitializerScope, this.currentPackage.annotations, this.scope.fPackage);
345             }
346             /*
347              * resolve javadoc package if any
348              * we do it now and the javadoc in the fake type won't be resolved
349              */

350             if (this.javadoc != null) {
351                 this.javadoc.resolve(syntheticTypeDeclaration.staticInitializerScope);
352             }
353             startingTypeIndex = 1;
354         } else {
355             // resolve compilation unit javadoc package if any
356
if (this.javadoc != null) {
357                 this.javadoc.resolve(this.scope);
358             }
359         }
360         if (this.currentPackage != null && this.currentPackage.annotations != null && !isPackageInfo) {
361             scope.problemReporter().invalidFileNameForPackageAnnotations(this.currentPackage.annotations[0]);
362         }
363         try {
364             if (types != null) {
365                 for (int i = startingTypeIndex, count = types.length; i < count; i++) {
366                     types[i].resolve(scope);
367                 }
368             }
369             if (!this.compilationResult.hasErrors()) checkUnusedImports();
370             reportNLSProblems();
371         } catch (AbortCompilationUnit e) {
372             this.ignoreFurtherInvestigation = true;
373             return;
374         }
375     }
376
377     private void reportNLSProblems() {
378         if (this.nlsTags != null || this.stringLiterals != null) {
379             final int stringLiteralsLength = this.stringLiteralsPtr;
380             final int nlsTagsLength = this.nlsTags == null ? 0 : this.nlsTags.length;
381             if (stringLiteralsLength == 0) {
382                 if (nlsTagsLength != 0) {
383                     for (int i = 0; i < nlsTagsLength; i++) {
384                         NLSTag tag = this.nlsTags[i];
385                         if (tag != null) {
386                             scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end);
387                         }
388                     }
389                 }
390             } else if (nlsTagsLength == 0) {
391                 // resize string literals
392
if (this.stringLiterals.length != stringLiteralsLength) {
393                     System.arraycopy(this.stringLiterals, 0, (stringLiterals = new StringLiteral[stringLiteralsLength]), 0, stringLiteralsLength);
394                 }
395                 Arrays.sort(this.stringLiterals, STRING_LITERAL_COMPARATOR);
396                 for (int i = 0; i < stringLiteralsLength; i++) {
397                     scope.problemReporter().nonExternalizedStringLiteral(this.stringLiterals[i]);
398                 }
399             } else {
400                 // need to iterate both arrays to find non matching elements
401
if (this.stringLiterals.length != stringLiteralsLength) {
402                     System.arraycopy(this.stringLiterals, 0, (stringLiterals = new StringLiteral[stringLiteralsLength]), 0, stringLiteralsLength);
403                 }
404                 Arrays.sort(this.stringLiterals, STRING_LITERAL_COMPARATOR);
405                 int indexInLine = 1;
406                 int lastLineNumber = -1;
407                 StringLiteral literal = null;
408                 int index = 0;
409                 int i = 0;
410                 stringLiteralsLoop: for (; i < stringLiteralsLength; i++) {
411                     literal = this.stringLiterals[i];
412                     final int literalLineNumber = literal.lineNumber;
413                     if (lastLineNumber != literalLineNumber) {
414                         indexInLine = 1;
415                         lastLineNumber = literalLineNumber;
416                     } else {
417                         indexInLine++;
418                     }
419                     if (index < nlsTagsLength) {
420                         nlsTagsLoop: for (; index < nlsTagsLength; index++) {
421                             NLSTag tag = this.nlsTags[index];
422                             if (tag == null) continue nlsTagsLoop;
423                             int tagLineNumber = tag.lineNumber;
424                             if (literalLineNumber < tagLineNumber) {
425                                 scope.problemReporter().nonExternalizedStringLiteral(literal);
426                                 continue stringLiteralsLoop;
427                             } else if (literalLineNumber == tagLineNumber) {
428                                 if (tag.index == indexInLine) {
429                                     this.nlsTags[index] = null;
430                                     index++;
431                                     continue stringLiteralsLoop;
432                                 } else {
433                                     nlsTagsLoop2: for (int index2 = index + 1; index2 < nlsTagsLength; index2++) {
434                                         NLSTag tag2 = this.nlsTags[index2];
435                                         if (tag2 == null) continue nlsTagsLoop2;
436                                         int tagLineNumber2 = tag2.lineNumber;
437                                         if (literalLineNumber == tagLineNumber2) {
438                                             if (tag2.index == indexInLine) {
439                                                 this.nlsTags[index2] = null;
440                                                 continue stringLiteralsLoop;
441                                             } else {
442                                                 continue nlsTagsLoop2;
443                                             }
444                                         } else {
445                                             scope.problemReporter().nonExternalizedStringLiteral(literal);
446                                             continue stringLiteralsLoop;
447                                         }
448                                     }
449                                     scope.problemReporter().nonExternalizedStringLiteral(literal);
450                                     continue stringLiteralsLoop;
451                                 }
452                             } else {
453                                 scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end);
454                                 continue nlsTagsLoop;
455                             }
456                         }
457                     }
458                     // all nls tags have been processed, so remaining string literals are not externalized
459
break stringLiteralsLoop;
460                 }
461                 for (; i < stringLiteralsLength; i++) {
462                     scope.problemReporter().nonExternalizedStringLiteral(this.stringLiterals[i]);
463                 }
464                 if (index < nlsTagsLength) {
465                     for (; index < nlsTagsLength; index++) {
466                         NLSTag tag = this.nlsTags[index];
467                         if (tag != null) {
468                             scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end);
469                         }
470                     }
471                 }
472             }
473         }
474     }
475
476     public void tagAsHavingErrors() {
477         ignoreFurtherInvestigation = true;
478     }
479
480     public void traverse(
481         ASTVisitor visitor,
482         CompilationUnitScope unitScope) {
483
484         if (ignoreFurtherInvestigation)
485             return;
486         try {
487             if (visitor.visit(this, this.scope)) {
488                 if (this.types != null && isPackageInfo()) {
489                     // resolve synthetic type declaration
490
final TypeDeclaration syntheticTypeDeclaration = types[0];
491                     // resolve javadoc package if any
492
final MethodScope methodScope = syntheticTypeDeclaration.staticInitializerScope;
493                     if (this.javadoc != null) {
494                         this.javadoc.traverse(visitor, methodScope);
495                     }
496                     if (this.currentPackage != null) {
497                         final Annotation[] annotations = this.currentPackage.annotations;
498                         if (annotations != null) {
499                             int annotationsLength = annotations.length;
500                             for (int i = 0; i < annotationsLength; i++) {
501                                 annotations[i].traverse(visitor, methodScope);
502                             }
503                         }
504                     }
505                 }
506                 if (this.currentPackage != null) {
507                     this.currentPackage.traverse(visitor, this.scope);
508                 }
509                 if (imports != null) {
510                     int importLength = imports.length;
511                     for (int i = 0; i < importLength; i++) {
512                         imports[i].traverse(visitor, this.scope);
513                     }
514                 }
515                 if (types != null) {
516                     int typesLength = types.length;
517                     for (int i = 0; i < typesLength; i++) {
518                         types[i].traverse(visitor, this.scope);
519                     }
520                 }
521             }
522             visitor.endVisit(this, this.scope);
523         } catch (AbortCompilationUnit e) {
524             // ignore
525
}
526     }
527 }
528
Popular Tags