added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / lookup / CompilationUnitScope.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.lookup;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.*;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
17 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
18 import org.eclipse.jdt.internal.compiler.util.*;
19
20 public class CompilationUnitScope extends Scope {
21         
22         public LookupEnvironment environment;
23         public CompilationUnitDeclaration referenceContext;
24         public char[][] currentPackageName;
25         public PackageBinding fPackage;
26         public ImportBinding[] imports;
27         public HashtableOfObject resolvedSingeTypeImports;
28         
29         public SourceTypeBinding[] topLevelTypes;
30
31         private CompoundNameVector qualifiedReferences;
32         private SimpleNameVector simpleNameReferences;
33         private ObjectVector referencedTypes;
34         private ObjectVector referencedSuperTypes;
35         
36         HashtableOfType constantPoolNameUsage;
37
38 public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
39         super(COMPILATION_UNIT_SCOPE, null);
40         this.environment = environment;
41         this.referenceContext = unit;
42         unit.scope = this;
43         this.currentPackageName = unit.currentPackage == null ? CharOperation.NO_CHAR_CHAR : unit.currentPackage.tokens;
44
45         if (environment.options.produceReferenceInfo) {
46                 this.qualifiedReferences = new CompoundNameVector();
47                 this.simpleNameReferences = new SimpleNameVector();
48                 this.referencedTypes = new ObjectVector();
49                 this.referencedSuperTypes = new ObjectVector();
50         } else {
51                 this.qualifiedReferences = null; // used to test if dependencies should be recorded
52                 this.simpleNameReferences = null;
53                 this.referencedTypes = null;
54                 this.referencedSuperTypes = null;
55         }
56 }
57 void buildFieldsAndMethods() {
58         for (int i = 0, length = topLevelTypes.length; i < length; i++)
59                 topLevelTypes[i].scope.buildFieldsAndMethods();
60 }
61 void buildTypeBindings(AccessRestriction accessRestriction) {
62         topLevelTypes = new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved
63         if (referenceContext.compilationResult.compilationUnit != null) {
64                 char[][] expectedPackageName = referenceContext.compilationResult.compilationUnit.getPackageName();
65                 if (expectedPackageName != null 
66                                 && !CharOperation.equals(currentPackageName, expectedPackageName)) {
67
68                         // only report if the unit isn't structurally empty
69                         if (referenceContext.currentPackage != null 
70                                         || referenceContext.types != null 
71                                         || referenceContext.imports != null) {
72                                 problemReporter().packageIsNotExpectedPackage(referenceContext);
73                         }
74                         currentPackageName = expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName;
75                 }
76         }
77         if (currentPackageName == CharOperation.NO_CHAR_CHAR) {
78                 if ((fPackage = environment.defaultPackage) == null) {
79                         problemReporter().mustSpecifyPackage(referenceContext);
80                         return;
81                 }
82         } else {
83                 if ((fPackage = environment.createPackage(currentPackageName)) == null) {
84                         problemReporter().packageCollidesWithType(referenceContext);
85                         return;
86                 }
87                 recordQualifiedReference(currentPackageName); // always dependent on your own package
88         }
89
90         // Skip typeDeclarations which know of previously reported errors
91         TypeDeclaration[] types = referenceContext.types;
92         int typeLength = (types == null) ? 0 : types.length;
93         topLevelTypes = new SourceTypeBinding[typeLength];
94         int count = 0;
95         nextType: for (int i = 0; i < typeLength; i++) {
96                 TypeDeclaration typeDecl = types[i];
97                 ReferenceBinding typeBinding = fPackage.getType0(typeDecl.name);
98                 recordSimpleReference(typeDecl.name); // needed to detect collision cases
99                 if (typeBinding != null && !(typeBinding instanceof UnresolvedReferenceBinding)) {
100                         // if a type exists, it must be a valid type - cannot be a NotFound problem type
101                         // unless its an unresolved type which is now being defined
102                         problemReporter().duplicateTypes(referenceContext, typeDecl);
103                         continue nextType;
104                 }
105                 if (fPackage != environment.defaultPackage && fPackage.getPackage(typeDecl.name) != null) {
106                         // if a package exists, it must be a valid package - cannot be a NotFound problem package
107                         problemReporter().typeCollidesWithPackage(referenceContext, typeDecl);
108                         continue nextType;
109                 }
110
111                 if ((typeDecl.modifiers & AccPublic) != 0) {
112                         char[] mainTypeName;
113                         if ((mainTypeName = referenceContext.getMainTypeName()) != null // mainTypeName == null means that implementor of ICompilationUnit decided to return null
114                                         && !CharOperation.equals(mainTypeName, typeDecl.name)) {
115                                 problemReporter().publicClassMustMatchFileName(referenceContext, typeDecl);
116                                 continue nextType;
117                         }
118                 }
119
120                 ClassScope child = new ClassScope(this, typeDecl);
121                 SourceTypeBinding type = child.buildType(null, fPackage, accessRestriction);
122                 if(type != null) {
123                         topLevelTypes[count++] = type;
124                 }
125         }
126
127         // shrink topLevelTypes... only happens if an error was reported
128         if (count != topLevelTypes.length)
129                 System.arraycopy(topLevelTypes, 0, topLevelTypes = new SourceTypeBinding[count], 0, count);
130 }
131 void checkAndSetImports() {
132         if (referenceContext.imports == null) {
133                 imports = getDefaultImports();
134                 return;
135         }
136
137         // allocate the import array, add java.lang.* by default
138         int numberOfStatements = referenceContext.imports.length;
139         int numberOfImports = numberOfStatements + 1;
140         for (int i = 0; i < numberOfStatements; i++) {
141                 ImportReference importReference = referenceContext.imports[i];
142                 if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens) && !importReference.isStatic()) {
143                         numberOfImports--;
144                         break;
145                 }
146         }
147         ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
148         resolvedImports[0] = getDefaultImports()[0];
149         int index = 1;
150
151         nextImport : for (int i = 0; i < numberOfStatements; i++) {
152                 ImportReference importReference = referenceContext.imports[i];
153                 char[][] compoundName = importReference.tokens;
154
155                 // skip duplicates or imports of the current package
156                 for (int j = 0; j < index; j++) {
157                         ImportBinding resolved = resolvedImports[j];
158                         if (resolved.onDemand == importReference.onDemand && resolved.isStatic() == importReference.isStatic())
159                                 if (CharOperation.equals(compoundName, resolvedImports[j].compoundName))
160                                         continue nextImport;
161                 }
162
163                 if (importReference.onDemand) {
164                         if (CharOperation.equals(compoundName, currentPackageName))
165                                 continue nextImport;
166
167                         Binding importBinding = findImport(compoundName, compoundName.length);
168                         if (!importBinding.isValidBinding() || (importReference.isStatic() && importBinding instanceof PackageBinding))
169                                 continue nextImport;    // we report all problems in faultInImports()
170                         resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference);
171                 } else {
172                         // resolve single imports only when the last name matches
173                         resolvedImports[index++] = new ImportBinding(compoundName, false, null, importReference);
174                 }
175         }
176
177         // shrink resolvedImports... only happens if an error was reported
178         if (resolvedImports.length > index)
179                 System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index);
180         imports = resolvedImports;
181 }
182 /*
183  * INTERNAL USE-ONLY
184  * Innerclasses get their name computed as they are generated, since some may not
185  * be actually outputed if sitting inside unreachable code.
186  */
187 public char[] computeConstantPoolName(LocalTypeBinding localType) {
188         if (localType.constantPoolName() != null) {
189                 return localType.constantPoolName();
190         }
191         // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes.
192
193         if (constantPoolNameUsage == null)
194                 constantPoolNameUsage = new HashtableOfType();
195
196         ReferenceBinding outerMostEnclosingType = localType.scope.outerMostClassScope().enclosingSourceType();
197         
198         // ensure there is not already such a local type name defined by the user
199         int index = 0;
200         char[] candidateName;
201         while(true) {
202                 if (localType.isMemberType()){
203                         if (index == 0){
204                                 candidateName = CharOperation.concat(
205                                         localType.enclosingType().constantPoolName(),
206                                         localType.sourceName,
207                                         '$');
208                         } else {
209                                 // in case of collision, then member name gets extra $1 inserted
210                                 // e.g. class X { { class L{} new X(){ class L{} } } }
211                                 candidateName = CharOperation.concat(
212                                         localType.enclosingType().constantPoolName(),
213                                         '$',
214                                         String.valueOf(index).toCharArray(),
215                                         '$',
216                                         localType.sourceName);
217                         }
218                 } else if (localType.isAnonymousType()){
219                                 candidateName = CharOperation.concat(
220                                         outerMostEnclosingType.constantPoolName(),
221                                         String.valueOf(index+1).toCharArray(),
222                                         '$');
223                 } else {
224                                 candidateName = CharOperation.concat(
225                                         outerMostEnclosingType.constantPoolName(),
226                                         '$',
227                                         String.valueOf(index+1).toCharArray(),
228                                         '$',
229                                         localType.sourceName);
230                 }                                               
231                 if (constantPoolNameUsage.get(candidateName) != null) {
232                         index ++;
233                 } else {
234                         constantPoolNameUsage.put(candidateName, localType);
235                         break;
236                 }
237         }
238         return candidateName;
239 }
240
241 void connectTypeHierarchy() {
242         for (int i = 0, length = topLevelTypes.length; i < length; i++)
243                 topLevelTypes[i].scope.connectTypeHierarchy();
244 }
245 void faultInImports() {
246         if (referenceContext.imports == null)
247                 return;
248
249         // collect the top level type names if a single type import exists
250         int numberOfStatements = referenceContext.imports.length;
251         HashtableOfType typesBySimpleNames = null;
252         for (int i = 0; i < numberOfStatements; i++) {
253                 if (!referenceContext.imports[i].onDemand) {
254                         typesBySimpleNames = new HashtableOfType(topLevelTypes.length + numberOfStatements);
255                         for (int j = 0, length = topLevelTypes.length; j < length; j++)
256                                 typesBySimpleNames.put(topLevelTypes[j].sourceName, topLevelTypes[j]);
257                         break;
258                 }
259         }
260
261         // allocate the import array, add java.lang.* by default
262         int numberOfImports = numberOfStatements + 1;
263         for (int i = 0; i < numberOfStatements; i++) {
264                 ImportReference importReference = referenceContext.imports[i];
265                 if (importReference.onDemand && CharOperation.equals(JAVA_LANG, importReference.tokens) && !importReference.isStatic()) {
266                         numberOfImports--;
267                         break;
268                 }
269         }
270         ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
271         resolvedImports[0] = getDefaultImports()[0];
272         int index = 1;
273
274         // keep static imports with normal imports until there is a reason to split them up
275         // on demand imports continue to be packages & types. need to check on demand type imports for fields/methods
276         // single imports change from being just types to types or fields
277         nextImport : for (int i = 0; i < numberOfStatements; i++) {
278                 ImportReference importReference = referenceContext.imports[i];
279                 char[][] compoundName = importReference.tokens;
280
281                 // skip duplicates or imports of the current package
282                 for (int j = 0; j < index; j++) {
283                         ImportBinding resolved = resolvedImports[j];
284                         if (resolved.onDemand == importReference.onDemand && resolved.isStatic() == importReference.isStatic()) {
285                                 if (CharOperation.equals(compoundName, resolved.compoundName)) {
286                                         problemReporter().unusedImport(importReference); // since skipped, must be reported now
287                                         continue nextImport;
288                                 }
289                         }
290                 }
291                 if (importReference.onDemand) {
292                         if (CharOperation.equals(compoundName, currentPackageName)) {
293                                 problemReporter().unusedImport(importReference); // since skipped, must be reported now
294                                 continue nextImport;
295                         }
296
297                         Binding importBinding = findImport(compoundName, compoundName.length);
298                         if (!importBinding.isValidBinding()) {
299                                 problemReporter().importProblem(importReference, importBinding);
300                                 continue nextImport;
301                         }
302                         if (importReference.isStatic() && importBinding instanceof PackageBinding) {
303                                 problemReporter().cannotImportPackage(importReference);
304                                 continue nextImport;
305                         }
306                         resolvedImports[index++] = new ImportBinding(compoundName, true, importBinding, importReference);
307                 } else {
308                         Binding importBinding = findSingleImport(compoundName, importReference.isStatic());
309                         if (!importBinding.isValidBinding()) {
310                                 problemReporter().importProblem(importReference, importBinding);
311                                 continue nextImport;
312                         }
313                         if (importBinding instanceof PackageBinding) {
314                                 problemReporter().cannotImportPackage(importReference);
315                                 continue nextImport;
316                         }
317                         // collisions between an imported static field & a type should be checked according to spec... but currently not by javac
318                         if (importBinding instanceof ReferenceBinding) {
319                                 ReferenceBinding referenceBinding = (ReferenceBinding) importBinding;
320                                 if (importReference.isTypeUseDeprecated(referenceBinding, this))
321                                         problemReporter().deprecatedType(referenceBinding, importReference);
322
323                                 ReferenceBinding existingType = typesBySimpleNames.get(compoundName[compoundName.length - 1]);
324                                 if (existingType != null) {
325                                         // duplicate test above should have caught this case, but make sure
326                                         if (existingType == referenceBinding)
327                                                 continue nextImport;
328                                         // either the type collides with a top level type or another imported type
329                                         for (int j = 0, length = topLevelTypes.length; j < length; j++) {
330                                                 if (CharOperation.equals(topLevelTypes[j].sourceName, existingType.sourceName)) {
331                                                         problemReporter().conflictingImport(importReference);
332                                                         continue nextImport;
333                                                 }
334                                         }
335                                         problemReporter().duplicateImport(importReference);
336                                         continue nextImport;
337                                 }
338                                 typesBySimpleNames.put(compoundName[compoundName.length - 1], referenceBinding);
339                         }
340                         resolvedImports[index++] = new ImportBinding(compoundName, false, importBinding, importReference);
341                 }
342         }
343
344         // shrink resolvedImports... only happens if an error was reported
345         if (resolvedImports.length > index)
346                 System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index);
347         imports = resolvedImports;
348
349         int length = imports.length;
350         resolvedSingeTypeImports = new HashtableOfObject(length);
351         for (int i = 0; i < length; i++) {
352                 ImportBinding binding = imports[i];
353                 if (!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding)
354                         resolvedSingeTypeImports.put(binding.compoundName[binding.compoundName.length - 1], binding);
355         }
356 }
357 public void faultInTypes() {
358         faultInImports();
359
360         for (int i = 0, length = topLevelTypes.length; i < length; i++)
361                 topLevelTypes[i].faultInTypesForFieldsAndMethods();
362 }
363 private Binding findImport(char[][] compoundName, int length) {
364         recordQualifiedReference(compoundName);
365
366         Binding binding = environment.getTopLevelPackage(compoundName[0]);
367         int i = 1;
368         foundNothingOrType: if (binding != null) {
369                 PackageBinding packageBinding = (PackageBinding) binding;
370                 while (i < length) {
371                         binding = packageBinding.getTypeOrPackage(compoundName[i++]);
372                         if (binding == null || !binding.isValidBinding()) {
373                                 binding = null;
374                                 break foundNothingOrType;
375                         }
376                         if (!(binding instanceof PackageBinding))
377                                 break foundNothingOrType;
378
379                         packageBinding = (PackageBinding) binding;
380                 }
381                 return packageBinding;
382         }
383
384         ReferenceBinding type;
385         if (binding == null) {
386                 if (environment.defaultPackage == null || environment.options.complianceLevel >= ClassFileConstants.JDK1_4)
387                         return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), NotFound);
388                 type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage);
389                 if (type == null || !type.isValidBinding())
390                         return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), NotFound);
391                 i = 1; // reset to look for member types inside the default package type
392         } else {
393                 type = (ReferenceBinding) binding;
394         }
395
396         while (i < length) {
397                 if (!type.canBeSeenBy(fPackage))
398                         return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), type, NotVisible);
399
400                 char[] name = compoundName[i++];
401                 // does not look for inherited member types on purpose, only immediate members
402                 type = type.getMemberType(name);
403                 if (type == null)
404                         return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), NotFound);
405         }
406         if (!type.canBeSeenBy(fPackage))
407                 return new ProblemReferenceBinding(compoundName, type, NotVisible);
408         return type;
409 }
410 private Binding findSingleImport(char[][] compoundName, boolean findStaticImports) {
411         if (compoundName.length == 1) {
412                 // findType records the reference
413                 // the name cannot be a package
414                 if (environment.defaultPackage == null || environment.options.complianceLevel >= ClassFileConstants.JDK1_4)
415                         return new ProblemReferenceBinding(compoundName, NotFound);
416                 ReferenceBinding typeBinding = findType(compoundName[0], environment.defaultPackage, fPackage);
417                 if (typeBinding == null)
418                         return new ProblemReferenceBinding(compoundName, NotFound);
419                 return typeBinding;
420         }
421
422         if (findStaticImports)
423                 return findSingleStaticImport(compoundName);
424         return findImport(compoundName, compoundName.length);
425 }
426 private Binding findSingleStaticImport(char[][] compoundName) {
427         Binding binding = findImport(compoundName, compoundName.length - 1);
428         if (!binding.isValidBinding()) return binding;
429
430         char[] name = compoundName[compoundName.length - 1];
431         if (binding instanceof PackageBinding) {
432                 Binding temp = ((PackageBinding) binding).getTypeOrPackage(name);
433                 if (temp != null && temp instanceof ReferenceBinding) // must resolve to a member type or field, not a top level type
434                         return new ProblemReferenceBinding(compoundName, InvalidTypeForStaticImport);
435                 return binding; // cannot be a package, error is caught in sender
436         }
437
438         // look to see if its a static field first
439         ReferenceBinding type = (ReferenceBinding) binding;
440         FieldBinding field = findField(type, name, null, true);
441         if (field != null && field.isStatic() && field.canBeSeenBy(fPackage))
442                 return field;
443
444         type = findMemberType(name, type);
445         if (type == null || !type.isStatic())
446                 return new ProblemReferenceBinding(compoundName, type, NotFound);
447         if (!type.canBeSeenBy(fPackage))
448                 return new ProblemReferenceBinding(compoundName, type, NotVisible);
449         return type;
450 }
451 ImportBinding[] getDefaultImports() {
452         // initialize the default imports if necessary... share the default java.lang.* import
453         if (environment.defaultImports != null) return environment.defaultImports;
454
455         Binding importBinding = environment.getTopLevelPackage(JAVA);
456         if (importBinding != null)
457                 importBinding = ((PackageBinding) importBinding).getTypeOrPackage(JAVA_LANG[1]);
458
459         // abort if java.lang cannot be found...
460         if (importBinding == null || !importBinding.isValidBinding())
461                 problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit());
462
463         return environment.defaultImports = new ImportBinding[] {new ImportBinding(JAVA_LANG, true, importBinding, null)};
464 }
465 // NOT Public API
466 public final Binding getImport(char[][] compoundName, boolean onDemand, boolean isStaticImport) {
467         if (onDemand)
468                 return findImport(compoundName, compoundName.length);
469         return findSingleImport(compoundName, isStaticImport);
470 }
471 /* Answer the problem reporter to use for raising new problems.
472 *
473 * Note that as a side-effect, this updates the current reference context
474 * (unit, type or method) in case the problem handler decides it is necessary
475 * to abort.
476 */
477
478 public ProblemReporter problemReporter() {
479         ProblemReporter problemReporter = referenceContext.problemReporter;
480         problemReporter.referenceContext = referenceContext;
481         return problemReporter;
482 }
483
484 /*
485 What do we hold onto:
486
487 1. when we resolve 'a.b.c', say we keep only 'a.b.c'
488  & when we fail to resolve 'c' in 'a.b', lets keep 'a.b.c'
489 THEN when we come across a new/changed/removed item named 'a.b.c',
490  we would find all references to 'a.b.c'
491 -> This approach fails because every type is resolved in every onDemand import to
492  detect collision cases... so the references could be 10 times bigger than necessary.
493
494 2. when we resolve 'a.b.c', lets keep 'a.b' & 'c'
495  & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'c'
496 THEN when we come across a new/changed/removed item named 'a.b.c',
497  we would find all references to 'a.b' & 'c'
498 -> This approach does not have a space problem but fails to handle collision cases.
499  What happens if a type is added named 'a.b'? We would search for 'a' & 'b' but
500  would not find a match.
501
502 3. when we resolve 'a.b.c', lets keep 'a', 'a.b' & 'a', 'b', 'c'
503  & when we fail to resolve 'c' in 'a.b', lets keep 'a', 'a.b' & 'a', 'b', 'c'
504 THEN when we come across a new/changed/removed item named 'a.b.c',
505  we would find all references to 'a.b' & 'c'
506 OR 'a.b' -> 'a' & 'b'
507 OR 'a' -> '' & 'a'
508 -> As long as each single char[] is interned, we should not have a space problem
509  and can handle collision cases.
510
511 4. when we resolve 'a.b.c', lets keep 'a.b' & 'a', 'b', 'c'
512  & when we fail to resolve 'c' in 'a.b', lets keep 'a.b' & 'a', 'b', 'c'
513 THEN when we come across a new/changed/removed item named 'a.b.c',
514  we would find all references to 'a.b' & 'c'
515 OR 'a.b' -> 'a' & 'b' in the simple name collection
516 OR 'a' -> 'a' in the simple name collection
517 -> As long as each single char[] is interned, we should not have a space problem
518  and can handle collision cases.
519 */
520 void recordQualifiedReference(char[][] qualifiedName) {
521         if (qualifiedReferences == null) return; // not recording dependencies
522
523         int length = qualifiedName.length;
524         if (length > 1) {
525                 while (!qualifiedReferences.contains(qualifiedName)) {
526                         qualifiedReferences.add(qualifiedName);
527                         if (length == 2) {
528                                 recordSimpleReference(qualifiedName[0]);
529                                 recordSimpleReference(qualifiedName[1]);
530                                 return;
531                         }
532                         length--;
533                         recordSimpleReference(qualifiedName[length]);
534                         System.arraycopy(qualifiedName, 0, qualifiedName = new char[length][], 0, length);
535                 }
536         } else if (length == 1) {
537                 recordSimpleReference(qualifiedName[0]);
538         }
539 }
540 void recordReference(char[][] qualifiedEnclosingName, char[] simpleName) {
541         recordQualifiedReference(qualifiedEnclosingName);
542         recordSimpleReference(simpleName);
543 }
544 void recordReference(ReferenceBinding type, char[] simpleName) {
545         ReferenceBinding actualType = typeToRecord(type);
546         if (actualType != null)
547                 recordReference(actualType.compoundName, simpleName);
548 }
549 void recordSimpleReference(char[] simpleName) {
550         if (simpleNameReferences == null) return; // not recording dependencies
551
552         if (!simpleNameReferences.contains(simpleName))
553                 simpleNameReferences.add(simpleName);
554 }
555 void recordSuperTypeReference(TypeBinding type) {
556         if (referencedSuperTypes == null) return; // not recording dependencies
557
558         ReferenceBinding actualType = typeToRecord(type);
559         if (actualType != null && !referencedSuperTypes.containsIdentical(actualType))
560                 referencedSuperTypes.add(actualType);
561 }
562 public void recordTypeConversion(TypeBinding superType, TypeBinding subType) {
563         recordSuperTypeReference(subType); // must record the hierarchy of the subType that is converted to the superType
564 }
565 void recordTypeReference(TypeBinding type) {
566         if (referencedTypes == null) return; // not recording dependencies
567
568         ReferenceBinding actualType = typeToRecord(type);
569         if (actualType != null && !referencedTypes.containsIdentical(actualType))
570                 referencedTypes.add(actualType);
571 }
572 void recordTypeReferences(TypeBinding[] types) {
573         if (referencedTypes == null) return; // not recording dependencies
574         if (types == null || types.length == 0) return;
575
576         for (int i = 0, max = types.length; i < max; i++) {
577                 // No need to record supertypes of method arguments & thrown exceptions, just the compoundName
578                 // If a field/method is retrieved from such a type then a separate call does the job
579                 ReferenceBinding actualType = typeToRecord(types[i]);
580                 if (actualType != null && !referencedTypes.containsIdentical(actualType))
581                         referencedTypes.add(actualType);
582         }
583 }
584 Binding resolveSingleImport(ImportBinding importBinding) {
585         if (importBinding.resolvedImport == null) {
586                 importBinding.resolvedImport = findSingleImport(importBinding.compoundName, importBinding.isStatic());
587                 if (!importBinding.resolvedImport.isValidBinding() || importBinding.resolvedImport instanceof PackageBinding) {
588                         if (this.imports != null) {
589                                 ImportBinding[] newImports = new ImportBinding[imports.length - 1];
590                                 for (int i = 0, n = 0, max = this.imports.length; i < max; i++)
591                                         if (this.imports[i] != importBinding)
592                                                 newImports[n++] = this.imports[i];
593                                 this.imports = newImports;
594                         }
595                         return null;
596                 }
597         }
598         return importBinding.resolvedImport;
599 }
600 public void storeDependencyInfo() {
601         // add the type hierarchy of each referenced supertype
602         // cannot do early since the hierarchy may not be fully resolved
603         for (int i = 0; i < referencedSuperTypes.size; i++) { // grows as more types are added
604                 ReferenceBinding type = (ReferenceBinding) referencedSuperTypes.elementAt(i);
605                 if (!referencedTypes.containsIdentical(type))
606                         referencedTypes.add(type);
607
608                 if (!type.isLocalType()) {
609                         ReferenceBinding enclosing = type.enclosingType();
610                         if (enclosing != null)
611                                 recordSuperTypeReference(enclosing);
612                 }
613                 ReferenceBinding superclass = type.superclass();
614                 if (superclass != null)
615                         recordSuperTypeReference(superclass);
616                 ReferenceBinding[] interfaces = type.superInterfaces();
617                 if (interfaces != null)
618                         for (int j = 0, length = interfaces.length; j < length; j++)
619                                 recordSuperTypeReference(interfaces[j]);
620         }
621
622         for (int i = 0, l = referencedTypes.size; i < l; i++) {
623                 ReferenceBinding type = (ReferenceBinding) referencedTypes.elementAt(i);
624                 if (!type.isLocalType())
625                         recordQualifiedReference(type.isMemberType()
626                                 ? CharOperation.splitOn('.', type.readableName())
627                                 : type.compoundName);
628         }
629
630         int size = qualifiedReferences.size;
631         char[][][] qualifiedRefs = new char[size][][];
632         for (int i = 0; i < size; i++)
633                 qualifiedRefs[i] = qualifiedReferences.elementAt(i);
634         referenceContext.compilationResult.qualifiedReferences = qualifiedRefs;
635
636         size = simpleNameReferences.size;
637         char[][] simpleRefs = new char[size][];
638         for (int i = 0; i < size; i++)
639                 simpleRefs[i] = simpleNameReferences.elementAt(i);
640         referenceContext.compilationResult.simpleNameReferences = simpleRefs;
641 }
642 public String toString() {
643         return "--- CompilationUnit Scope : " + new String(referenceContext.getFileName()); //$NON-NLS-1$
644 }
645 private ReferenceBinding typeToRecord(TypeBinding type) {
646         if (type.isArrayType())
647                 type = ((ArrayBinding) type).leafComponentType;
648
649         switch (type.kind()) {
650                 case Binding.TYPE_PARAMETER :
651                 case Binding.WILDCARD_TYPE :
652                         return null;
653                 case Binding.PARAMETERIZED_TYPE :
654                 case Binding.RAW_TYPE :
655                         type = type.erasure();
656         }
657
658         if (type instanceof ReferenceBinding) {
659                 ReferenceBinding refType = (ReferenceBinding) type;
660                 if (!refType.isLocalType()) return refType;
661         }
662         return null;
663 }
664 public void verifyMethods(MethodVerifier verifier) {
665         for (int i = 0, length = topLevelTypes.length; i < length; i++)
666                 topLevelTypes[i].verifyMethods(verifier);
667 }
668 }