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