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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
15 import net.sourceforge.phpdt.internal.compiler.env.IBinaryType;
16 import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment;
17 import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer;
18 import net.sourceforge.phpdt.internal.compiler.impl.ITypeRequestor;
19 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
20 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfPackage;
21 import net.sourceforge.phpdt.internal.compiler.util.Util;
23 public class LookupEnvironment implements BaseTypes, ProblemReasons,
25 // public CompilerOptions options;
26 public ProblemReporter problemReporter;
28 public ITypeRequestor typeRequestor;
30 PackageBinding defaultPackage;
32 ImportBinding[] defaultImports;
34 HashtableOfPackage knownPackages;
36 static final ProblemPackageBinding TheNotFoundPackage = new ProblemPackageBinding(
37 CharOperation.NO_CHAR, NotFound);
39 static final ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(
40 CharOperation.NO_CHAR, NotFound);
42 private INameEnvironment nameEnvironment;
44 private MethodVerifier verifier;
46 private ArrayBinding[][] uniqueArrayBindings;
48 private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4];
50 private int lastUnitIndex = -1;
52 private int lastCompletedUnitIndex = -1;
54 // indicate in which step on the compilation we are.
55 // step 1 : build the reference binding
56 // step 2 : conect the hierarchy (connect bindings)
57 // step 3 : build fields and method bindings.
58 private int stepCompleted;
60 final static int BUILD_TYPE_HIERARCHY = 1;
62 final static int CHECK_AND_SET_IMPORTS = 2;
64 final static int CONNECT_TYPE_HIERARCHY = 3;
66 final static int BUILD_FIELDS_AND_METHODS = 4;
68 public LookupEnvironment(ITypeRequestor typeRequestor,
69 ProblemReporter problemReporter, INameEnvironment nameEnvironment) {
70 // CompilerOptions options, ProblemReporter problemReporter,
71 // INameEnvironment nameEnvironment) {
72 this.typeRequestor = typeRequestor;
73 // this.options = options;
74 this.problemReporter = problemReporter;
75 this.defaultPackage = new PackageBinding(this); // assume the default
76 // package always exists
77 this.defaultImports = null;
78 this.nameEnvironment = nameEnvironment;
79 this.knownPackages = new HashtableOfPackage();
80 this.uniqueArrayBindings = new ArrayBinding[5][];
81 this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the
88 * Ask the oracle for a type which corresponds to the compoundName. Answer
89 * null if the name cannot be found.
92 public ReferenceBinding askForType(char[][] compoundName) {
93 NameEnvironmentAnswer answer = nameEnvironment.findType(compoundName);
97 if (answer.isBinaryType())
98 // the type was found as a .class file
99 typeRequestor.accept(answer.getBinaryType(),
100 computePackageFrom(compoundName));
101 else if (answer.isCompilationUnit())
102 // the type was found as a .java file, try to build it then search
104 typeRequestor.accept(answer.getCompilationUnit());
105 else if (answer.isSourceType())
106 // the type was found as a source model
107 typeRequestor.accept(answer.getSourceTypes(),
108 computePackageFrom(compoundName));
110 return getCachedType(compoundName);
114 * Ask the oracle for a type named name in the packageBinding. Answer null
115 * if the name cannot be found.
118 ReferenceBinding askForType(PackageBinding packageBinding, char[] name) {
119 if (packageBinding == null) {
120 if (defaultPackage == null)
122 packageBinding = defaultPackage;
124 NameEnvironmentAnswer answer = nameEnvironment.findType(name,
125 packageBinding.compoundName);
129 if (answer.isBinaryType())
130 // the type was found as a .class file
131 typeRequestor.accept(answer.getBinaryType(), packageBinding);
132 else if (answer.isCompilationUnit())
133 // the type was found as a .java file, try to build it then search
135 typeRequestor.accept(answer.getCompilationUnit());
136 else if (answer.isSourceType())
137 // the type was found as a source model
138 typeRequestor.accept(answer.getSourceTypes(), packageBinding);
140 return packageBinding.getType0(name);
144 * Create the initial type bindings for the compilation unit.
146 * See completeTypeBindings() for a description of the remaining steps
148 * NOTE: This method can be called multiple times as additional source files
152 public void buildTypeBindings(CompilationUnitDeclaration unit) {
153 CompilationUnitScope scope = new CompilationUnitScope(unit, this);
154 scope.buildTypeBindings();
156 int unitsLength = units.length;
157 if (++lastUnitIndex >= unitsLength)
158 System.arraycopy(units, 0,
159 units = new CompilationUnitDeclaration[2 * unitsLength], 0,
161 units[lastUnitIndex] = unit;
165 * Cache the binary type since we know it is needed during this compile.
167 * Answer the created BinaryTypeBinding or null if the type is already in
171 public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType) {
172 return cacheBinaryType(binaryType, true);
176 * Cache the binary type since we know it is needed during this compile.
178 * Answer the created BinaryTypeBinding or null if the type is already in
182 public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType,
183 boolean needFieldsAndMethods) {
184 char[][] compoundName = CharOperation
185 .splitOn('/', binaryType.getName());
186 ReferenceBinding existingType = getCachedType(compoundName);
188 if (existingType == null
189 || existingType instanceof UnresolvedReferenceBinding)
190 // only add the binary type if its not already in the cache
191 return createBinaryTypeFrom(binaryType,
192 computePackageFrom(compoundName), needFieldsAndMethods);
193 return null; // the type already exists & can be retrieved from the
198 * 1. Connect the type hierarchy for the type bindings created for
199 * parsedUnits. 2. Create the field bindings 3. Create the method bindings
203 * We know each known compilationUnit is free of errors at this point...
205 * Each step will create additional bindings unless a problem is detected,
206 * in which case either the faulty import/superinterface/field/method will
207 * be skipped or a suitable replacement will be substituted (such as Object
208 * for a missing superclass)
211 public void completeTypeBindings() {
212 stepCompleted = BUILD_TYPE_HIERARCHY;
214 // for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
215 // units[i].scope.checkAndSetImports();
217 stepCompleted = CHECK_AND_SET_IMPORTS;
219 // for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
220 // units[i].scope.connectTypeHierarchy();
222 stepCompleted = CONNECT_TYPE_HIERARCHY;
224 for (int i = lastCompletedUnitIndex + 1; i <= lastUnitIndex; i++) {
225 // units[i].scope.buildFieldsAndMethods();
226 units[i] = null; // release unnecessary reference to the parsed
229 stepCompleted = BUILD_FIELDS_AND_METHODS;
230 lastCompletedUnitIndex = lastUnitIndex;
234 * 1. Connect the type hierarchy for the type bindings created for
235 * parsedUnits. 2. Create the field bindings 3. Create the method bindings
239 * Each step will create additional bindings unless a problem is detected,
240 * in which case either the faulty import/superinterface/field/method will
241 * be skipped or a suitable replacement will be substituted (such as Object
242 * for a missing superclass)
245 public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) {
246 if (stepCompleted == BUILD_FIELDS_AND_METHODS) {
247 // This can only happen because the original set of units are
248 // completely built and
249 // are now being processed, so we want to treat all the additional
251 // until they too are completely processed.
252 completeTypeBindings();
254 if (parsedUnit.scope == null)
255 return; // parsing errors were too severe
257 // if (stepCompleted >= CHECK_AND_SET_IMPORTS)
258 // parsedUnit.scope.checkAndSetImports();
260 if (stepCompleted >= CONNECT_TYPE_HIERARCHY)
261 parsedUnit.scope.connectTypeHierarchy();
266 * Used by other compiler tools which do not start by calling
267 * completeTypeBindings().
269 * 1. Connect the type hierarchy for the type bindings created for
270 * parsedUnits. 2. Create the field bindings 3. Create the method bindings
273 public void completeTypeBindings(CompilationUnitDeclaration parsedUnit,
274 boolean buildFieldsAndMethods) {
275 if (parsedUnit.scope == null)
276 return; // parsing errors were too severe
278 parsedUnit.scope.checkAndSetImports();
279 parsedUnit.scope.connectTypeHierarchy();
281 if (buildFieldsAndMethods)
282 parsedUnit.scope.buildFieldsAndMethods();
285 private PackageBinding computePackageFrom(char[][] constantPoolName) {
286 if (constantPoolName.length == 1)
287 return defaultPackage;
289 PackageBinding packageBinding = getPackage0(constantPoolName[0]);
290 if (packageBinding == null || packageBinding == TheNotFoundPackage) {
291 packageBinding = new PackageBinding(constantPoolName[0], this);
292 knownPackages.put(constantPoolName[0], packageBinding);
295 for (int i = 1, length = constantPoolName.length - 1; i < length; i++) {
296 PackageBinding parent = packageBinding;
297 if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null
298 || packageBinding == TheNotFoundPackage) {
299 packageBinding = new PackageBinding(CharOperation.subarray(
300 constantPoolName, 0, i + 1), parent, this);
301 parent.addPackage(packageBinding);
304 return packageBinding;
308 * Used to guarantee array type identity.
311 ArrayBinding createArrayType(TypeBinding type, int dimensionCount) {
312 if (type instanceof LocalTypeBinding) // cache local type arrays with
313 // the local type itself
314 return ((LocalTypeBinding) type).createArrayType(dimensionCount);
316 // find the array binding cache for this dimension
317 int dimIndex = dimensionCount - 1;
318 int length = uniqueArrayBindings.length;
319 ArrayBinding[] arrayBindings;
320 if (dimIndex < length) {
321 if ((arrayBindings = uniqueArrayBindings[dimIndex]) == null)
322 uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10];
324 System.arraycopy(uniqueArrayBindings, 0,
325 uniqueArrayBindings = new ArrayBinding[dimensionCount][],
327 uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10];
330 // find the cached array binding for this leaf component type (if any)
332 length = arrayBindings.length;
333 while (++index < length) {
334 ArrayBinding currentBinding = arrayBindings[index];
335 if (currentBinding == null) // no matching array, but space left
336 return arrayBindings[index] = new ArrayBinding(type,
338 if (currentBinding.leafComponentType == type)
339 return currentBinding;
342 // no matching array, no space left
343 System.arraycopy(arrayBindings, 0,
344 (arrayBindings = new ArrayBinding[length * 2]), 0, length);
345 uniqueArrayBindings[dimIndex] = arrayBindings;
346 return arrayBindings[length] = new ArrayBinding(type, dimensionCount);
349 public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType,
350 PackageBinding packageBinding) {
351 return createBinaryTypeFrom(binaryType, packageBinding, true);
354 public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType,
355 PackageBinding packageBinding, boolean needFieldsAndMethods) {
356 BinaryTypeBinding binaryBinding = new BinaryTypeBinding(packageBinding,
359 // resolve any array bindings which reference the unresolvedType
360 ReferenceBinding cachedType = packageBinding
361 .getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]);
362 if (cachedType != null) {
363 if (cachedType.isBinaryBinding()) // sanity check before the
364 // cast... at this point the
365 // cache should ONLY contain
367 return (BinaryTypeBinding) cachedType;
369 UnresolvedReferenceBinding unresolvedType = (UnresolvedReferenceBinding) cachedType;
370 unresolvedType.resolvedType = binaryBinding;
371 updateArrayCache(unresolvedType, binaryBinding);
374 packageBinding.addType(binaryBinding);
375 binaryBinding.cachePartsFrom(binaryType, needFieldsAndMethods);
376 return binaryBinding;
380 * Used to create packages from the package statement.
383 PackageBinding createPackage(char[][] compoundName) {
385 // PackageBinding packageBinding = getPackage0(compoundName[0]);
386 // if (packageBinding == null || packageBinding == TheNotFoundPackage) {
387 // packageBinding = new PackageBinding(compoundName[0], this);
388 // knownPackages.put(compoundName[0], packageBinding);
391 // for (int i = 1, length = compoundName.length; i < length; i++) {
392 // // check to see if it collides with a known type...
393 // // this case can only happen if the package does not exist as a
394 // directory in the file system
395 // // otherwise when the source type was defined, the correct error
396 // would have been reported
397 // // unless its an unresolved type which is referenced from an
398 // inconsistent class file
399 // ReferenceBinding type = packageBinding.getType0(compoundName[i]);
400 // if (type != null && type != TheNotFoundType && !(type instanceof
401 // UnresolvedReferenceBinding))
404 // PackageBinding parent = packageBinding;
405 // if ((packageBinding = parent.getPackage0(compoundName[i])) == null ||
406 // packageBinding == TheNotFoundPackage) {
407 // // if the package is unknown, check to see if a type exists which
408 // would collide with the new package
409 // // catches the case of a package statement of: package
411 // // since the package can be added after a set of source files have
412 // already been compiled, we need
413 // // whenever a package statement is encountered
414 // if (nameEnvironment.findType(compoundName[i], parent.compoundName) !=
418 // packageBinding = new
419 // PackageBinding(CharOperation.subarray(compoundName, 0, i + 1),
421 // parent.addPackage(packageBinding);
424 // return packageBinding;
428 * Answer the type for the compoundName if it exists in the cache. Answer
429 * theNotFoundType if it could not be resolved the first time it was looked
430 * up, otherwise answer null.
432 * NOTE: Do not use for nested types... the answer is NOT the same for a.b.C
433 * or a.b.C.D.E assuming C is a type in both cases. In the a.b.C.D.E case,
434 * null is the answer.
437 public ReferenceBinding getCachedType(char[][] compoundName) {
438 if (compoundName.length == 1) {
439 if (defaultPackage == null)
441 return defaultPackage.getType0(compoundName[0]);
444 PackageBinding packageBinding = getPackage0(compoundName[0]);
445 if (packageBinding == null || packageBinding == TheNotFoundPackage)
448 for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++)
449 if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null
450 || packageBinding == TheNotFoundPackage)
452 return packageBinding.getType0(compoundName[compoundName.length - 1]);
456 * Answer the top level package named name if it exists in the cache. Answer
457 * theNotFoundPackage if it could not be resolved the first time it was
458 * looked up, otherwise answer null.
460 * NOTE: Senders must convert theNotFoundPackage into a real problem package
461 * if its to returned.
464 PackageBinding getPackage0(char[] name) {
465 return knownPackages.get(name);
469 * Answer the top level package named name. Ask the oracle for the package
470 * if its not in the cache. Answer null if the package cannot be found.
473 PackageBinding getTopLevelPackage(char[] name) {
474 PackageBinding packageBinding = getPackage0(name);
475 if (packageBinding != null) {
476 if (packageBinding == TheNotFoundPackage)
479 return packageBinding;
482 if (nameEnvironment.isPackage(null, name)) {
483 knownPackages.put(name, packageBinding = new PackageBinding(name,
485 return packageBinding;
488 knownPackages.put(name, TheNotFoundPackage); // saves asking the
494 * Answer the type corresponding to the compoundName. Ask the oracle for the
495 * type if its not in the cache. Answer null if the type cannot be found...
496 * likely a fatal error.
499 public ReferenceBinding getType(char[][] compoundName) {
500 ReferenceBinding referenceBinding;
502 if (compoundName.length == 1) {
503 if (defaultPackage == null)
506 if ((referenceBinding = defaultPackage.getType0(compoundName[0])) == null) {
507 PackageBinding packageBinding = getPackage0(compoundName[0]);
508 if (packageBinding != null
509 && packageBinding != TheNotFoundPackage)
510 return null; // collides with a known package... should
511 // not call this method in such a case
512 referenceBinding = askForType(defaultPackage, compoundName[0]);
515 PackageBinding packageBinding = getPackage0(compoundName[0]);
516 if (packageBinding == TheNotFoundPackage)
519 if (packageBinding != null) {
520 for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) {
521 if ((packageBinding = packageBinding
522 .getPackage0(compoundName[i])) == null)
524 if (packageBinding == TheNotFoundPackage)
529 if (packageBinding == null)
530 referenceBinding = askForType(compoundName);
531 else if ((referenceBinding = packageBinding
532 .getType0(compoundName[compoundName.length - 1])) == null)
533 referenceBinding = askForType(packageBinding,
534 compoundName[compoundName.length - 1]);
537 if (referenceBinding == null || referenceBinding == TheNotFoundType)
539 if (referenceBinding instanceof UnresolvedReferenceBinding)
540 referenceBinding = ((UnresolvedReferenceBinding) referenceBinding)
543 // compoundName refers to a nested type incorrectly (for example,
545 if (referenceBinding.isNestedType())
546 return new ProblemReferenceBinding(compoundName,
547 InternalNameProvided);
549 return referenceBinding;
553 * Answer the type corresponding to the name from the binary file. Does not
554 * ask the oracle for the type if its not found in the cache... instead an
555 * unresolved type is returned which must be resolved before used.
557 * NOTE: Does NOT answer base types nor array types!
559 * NOTE: Aborts compilation if the class file cannot be found.
562 ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start,
565 end = signature.length;
567 char[][] compoundName = CharOperation.splitOn('/', signature, start,
569 ReferenceBinding binding = getCachedType(compoundName);
570 if (binding == null) {
571 PackageBinding packageBinding = computePackageFrom(compoundName);
572 binding = new UnresolvedReferenceBinding(compoundName,
574 packageBinding.addType(binding);
575 } else if (binding == TheNotFoundType) {
576 problemReporter.isClassPathCorrect(compoundName, null);
577 return null; // will not get here since the above error aborts
584 * Answer the type corresponding to the signature from the binary file. Does
585 * not ask the oracle for the type if its not found in the cache... instead
586 * an unresolved type is returned which must be resolved before used.
588 * NOTE: Does answer base types & array types.
590 * NOTE: Aborts compilation if the class file cannot be found.
593 TypeBinding getTypeFromSignature(char[] signature, int start, int end) {
595 while (signature[start] == '[') {
600 end = signature.length - 1;
602 // Just switch on signature[start] - the L case is the else
603 TypeBinding binding = null;
605 switch (signature[start]) {
607 binding = IntBinding;
610 binding = BooleanBinding;
613 binding = VoidBinding;
616 binding = CharBinding;
619 binding = DoubleBinding;
622 binding = ByteBinding;
625 binding = FloatBinding;
628 binding = LongBinding;
631 binding = ShortBinding;
637 "error.undefinedBaseType", String.valueOf(signature[start]))); //$NON-NLS-1$
640 binding = getTypeFromConstantPoolName(signature, start + 1, end);
646 return createArrayType(binding, dimension);
650 * Ask the oracle if a package exists named name in the package named
654 boolean isPackage(char[][] compoundName, char[] name) {
655 if (compoundName == null || compoundName.length == 0)
656 return nameEnvironment.isPackage(null, name);
658 return nameEnvironment.isPackage(compoundName, name);
661 // The method verifier is lazily initialized to guarantee the receiver, the
662 // compiler & the oracle are ready.
664 public MethodVerifier methodVerifier() {
665 if (verifier == null)
666 verifier = new MethodVerifier(this);
670 public void reset() {
671 this.defaultPackage = new PackageBinding(this); // assume the default
672 // package always exists
673 this.defaultImports = null;
674 this.knownPackages = new HashtableOfPackage();
676 this.verifier = null;
677 for (int i = this.uniqueArrayBindings.length; --i >= 0;)
678 this.uniqueArrayBindings[i] = null;
679 this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the
684 for (int i = this.units.length; --i >= 0;)
685 this.units[i] = null;
686 this.lastUnitIndex = -1;
687 this.lastCompletedUnitIndex = -1;
689 // name environment has a longer life cycle, and must be reset in
690 // the code which created it.
693 void updateArrayCache(UnresolvedReferenceBinding unresolvedType,
694 ReferenceBinding resolvedType) {
695 nextDimension: for (int i = 0, length = uniqueArrayBindings.length; i < length; i++) {
696 ArrayBinding[] arrayBindings = uniqueArrayBindings[i];
697 if (arrayBindings != null) {
698 for (int j = 0, max = arrayBindings.length; j < max; j++) {
699 ArrayBinding currentBinding = arrayBindings[j];
700 if (currentBinding == null)
701 continue nextDimension;
702 if (currentBinding.leafComponentType == unresolvedType) {
703 currentBinding.leafComponentType = resolvedType;
704 continue nextDimension;