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