1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
15 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
16 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
17 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
18 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
19 import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
20 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
21 import org.eclipse.jdt.internal.compiler.util.HashtableOfPackage;
22 import org.eclipse.jdt.internal.compiler.util.Util;
24 public class LookupEnvironment implements BaseTypes, ProblemReasons, TypeConstants {
25 public CompilerOptions options;
26 public ProblemReporter problemReporter;
27 public ITypeRequestor typeRequestor;
29 PackageBinding defaultPackage;
30 ImportBinding[] defaultImports;
31 HashtableOfPackage knownPackages;
32 static final ProblemPackageBinding TheNotFoundPackage = new ProblemPackageBinding(CharOperation.NO_CHAR, NotFound);
33 static final ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(CharOperation.NO_CHAR, NotFound);
35 private INameEnvironment nameEnvironment;
36 private MethodVerifier verifier;
37 private ArrayBinding[][] uniqueArrayBindings;
39 private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4];
40 private int lastUnitIndex = -1;
41 private int lastCompletedUnitIndex = -1;
42 public CompilationUnitDeclaration unitBeingCompleted = null; // only set while completing units
44 // indicate in which step on the compilation we are.
45 // step 1 : build the reference binding
46 // step 2 : conect the hierarchy (connect bindings)
47 // step 3 : build fields and method bindings.
48 private int stepCompleted;
49 final static int BUILD_TYPE_HIERARCHY = 1;
50 final static int CHECK_AND_SET_IMPORTS = 2;
51 final static int CONNECT_TYPE_HIERARCHY = 3;
52 final static int BUILD_FIELDS_AND_METHODS = 4;
54 // shared byte[]'s used by ClassFile to avoid allocating MBs during a build
55 public boolean sharedArraysUsed = true; // set to false once actual arrays are allocated
56 public byte[] sharedClassFileHeader = null;
57 public byte[] sharedClassFileContents = null;
59 public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions options, ProblemReporter problemReporter, INameEnvironment nameEnvironment) {
60 this.typeRequestor = typeRequestor;
61 this.options = options;
62 this.problemReporter = problemReporter;
63 this.defaultPackage = new PackageBinding(this); // assume the default package always exists
64 this.defaultImports = null;
65 this.nameEnvironment = nameEnvironment;
66 this.knownPackages = new HashtableOfPackage();
67 this.uniqueArrayBindings = new ArrayBinding[5][];
68 this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the most common 1 dimension array @ 50
70 /* Ask the oracle for a type which corresponds to the compoundName.
71 * Answer null if the name cannot be found.
74 public ReferenceBinding askForType(char[][] compoundName) {
75 NameEnvironmentAnswer answer = nameEnvironment.findType(compoundName);
79 if (answer.isBinaryType())
80 // the type was found as a .class file
81 typeRequestor.accept(answer.getBinaryType(), computePackageFrom(compoundName));
82 else if (answer.isCompilationUnit())
83 // the type was found as a .java file, try to build it then search the cache
84 typeRequestor.accept(answer.getCompilationUnit());
85 else if (answer.isSourceType())
86 // the type was found as a source model
87 typeRequestor.accept(answer.getSourceTypes(), computePackageFrom(compoundName));
89 return getCachedType(compoundName);
91 /* Ask the oracle for a type named name in the packageBinding.
92 * Answer null if the name cannot be found.
95 ReferenceBinding askForType(PackageBinding packageBinding, char[] name) {
96 if (packageBinding == null) {
97 if (defaultPackage == null)
99 packageBinding = defaultPackage;
101 NameEnvironmentAnswer answer = nameEnvironment.findType(name, packageBinding.compoundName);
105 if (answer.isBinaryType())
106 // the type was found as a .class file
107 typeRequestor.accept(answer.getBinaryType(), packageBinding);
108 else if (answer.isCompilationUnit())
109 // the type was found as a .java file, try to build it then search the cache
110 typeRequestor.accept(answer.getCompilationUnit());
111 else if (answer.isSourceType())
112 // the type was found as a source model
113 typeRequestor.accept(answer.getSourceTypes(), packageBinding);
115 return packageBinding.getType0(name);
117 /* Create the initial type bindings for the compilation unit.
119 * See completeTypeBindings() for a description of the remaining steps
121 * NOTE: This method can be called multiple times as additional source files are needed
124 public void buildTypeBindings(CompilationUnitDeclaration unit) {
125 CompilationUnitScope scope = new CompilationUnitScope(unit, this);
126 scope.buildTypeBindings();
128 int unitsLength = units.length;
129 if (++lastUnitIndex >= unitsLength)
130 System.arraycopy(units, 0, units = new CompilationUnitDeclaration[2 * unitsLength], 0, unitsLength);
131 units[lastUnitIndex] = unit;
133 /* Cache the binary type since we know it is needed during this compile.
135 * Answer the created BinaryTypeBinding or null if the type is already in the cache.
138 public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType) {
139 return cacheBinaryType(binaryType, true);
141 /* Cache the binary type since we know it is needed during this compile.
143 * Answer the created BinaryTypeBinding or null if the type is already in the cache.
146 public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType, boolean needFieldsAndMethods) {
147 char[][] compoundName = CharOperation.splitOn('/', binaryType.getName());
148 ReferenceBinding existingType = getCachedType(compoundName);
150 if (existingType == null || existingType instanceof UnresolvedReferenceBinding)
151 // only add the binary type if its not already in the cache
152 return createBinaryTypeFrom(binaryType, computePackageFrom(compoundName), needFieldsAndMethods);
153 return null; // the type already exists & can be retrieved from the cache
156 * 1. Connect the type hierarchy for the type bindings created for parsedUnits.
157 * 2. Create the field bindings
158 * 3. Create the method bindings
161 /* We know each known compilationUnit is free of errors at this point...
163 * Each step will create additional bindings unless a problem is detected, in which
164 * case either the faulty import/superinterface/field/method will be skipped or a
165 * suitable replacement will be substituted (such as Object for a missing superclass)
168 public void completeTypeBindings() {
169 stepCompleted = BUILD_TYPE_HIERARCHY;
171 for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
172 (this.unitBeingCompleted = this.units[i]).scope.checkAndSetImports();
174 stepCompleted = CHECK_AND_SET_IMPORTS;
176 for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
177 (this.unitBeingCompleted = this.units[i]).scope.connectTypeHierarchy();
179 stepCompleted = CONNECT_TYPE_HIERARCHY;
181 for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
182 (this.unitBeingCompleted = this.units[i]).scope.buildFieldsAndMethods();
183 this.units[i] = null; // release unnecessary reference to the parsed unit
185 stepCompleted = BUILD_FIELDS_AND_METHODS;
186 this.lastCompletedUnitIndex = this.lastUnitIndex;
187 this.unitBeingCompleted = null;
190 * 1. Connect the type hierarchy for the type bindings created for parsedUnits.
191 * 2. Create the field bindings
192 * 3. Create the method bindings
196 * Each step will create additional bindings unless a problem is detected, in which
197 * case either the faulty import/superinterface/field/method will be skipped or a
198 * suitable replacement will be substituted (such as Object for a missing superclass)
201 public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) {
202 if (stepCompleted == BUILD_FIELDS_AND_METHODS) {
203 // This can only happen because the original set of units are completely built and
204 // are now being processed, so we want to treat all the additional units as a group
205 // until they too are completely processed.
206 completeTypeBindings();
208 if (parsedUnit.scope == null) return; // parsing errors were too severe
210 if (stepCompleted >= CHECK_AND_SET_IMPORTS)
211 (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports();
213 if (stepCompleted >= CONNECT_TYPE_HIERARCHY)
214 (this.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy();
216 this.unitBeingCompleted = null;
220 * Used by other compiler tools which do not start by calling completeTypeBindings().
222 * 1. Connect the type hierarchy for the type bindings created for parsedUnits.
223 * 2. Create the field bindings
224 * 3. Create the method bindings
227 public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, boolean buildFieldsAndMethods) {
228 if (parsedUnit.scope == null) return; // parsing errors were too severe
230 (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports();
231 parsedUnit.scope.connectTypeHierarchy();
232 if (buildFieldsAndMethods)
233 parsedUnit.scope.buildFieldsAndMethods();
234 this.unitBeingCompleted = null;
236 private PackageBinding computePackageFrom(char[][] constantPoolName) {
237 if (constantPoolName.length == 1)
238 return defaultPackage;
240 PackageBinding packageBinding = getPackage0(constantPoolName[0]);
241 if (packageBinding == null || packageBinding == TheNotFoundPackage) {
242 packageBinding = new PackageBinding(constantPoolName[0], this);
243 knownPackages.put(constantPoolName[0], packageBinding);
246 for (int i = 1, length = constantPoolName.length - 1; i < length; i++) {
247 PackageBinding parent = packageBinding;
248 if ((packageBinding = parent.getPackage0(constantPoolName[i])) == null || packageBinding == TheNotFoundPackage) {
249 packageBinding = new PackageBinding(CharOperation.subarray(constantPoolName, 0, i + 1), parent, this);
250 parent.addPackage(packageBinding);
253 return packageBinding;
255 /* Used to guarantee array type identity.
258 ArrayBinding createArrayType(TypeBinding type, int dimensionCount) {
259 if (type instanceof LocalTypeBinding) // cache local type arrays with the local type itself
260 return ((LocalTypeBinding) type).createArrayType(dimensionCount);
262 // find the array binding cache for this dimension
263 int dimIndex = dimensionCount - 1;
264 int length = uniqueArrayBindings.length;
265 ArrayBinding[] arrayBindings;
266 if (dimIndex < length) {
267 if ((arrayBindings = uniqueArrayBindings[dimIndex]) == null)
268 uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10];
271 uniqueArrayBindings, 0,
272 uniqueArrayBindings = new ArrayBinding[dimensionCount][], 0,
274 uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10];
277 // find the cached array binding for this leaf component type (if any)
279 length = arrayBindings.length;
280 while (++index < length) {
281 ArrayBinding currentBinding = arrayBindings[index];
282 if (currentBinding == null) // no matching array, but space left
283 return arrayBindings[index] = new ArrayBinding(type, dimensionCount);
284 if (currentBinding.leafComponentType == type)
285 return currentBinding;
288 // no matching array, no space left
291 (arrayBindings = new ArrayBinding[length * 2]), 0,
293 uniqueArrayBindings[dimIndex] = arrayBindings;
294 return arrayBindings[length] = new ArrayBinding(type, dimensionCount);
296 public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding) {
297 return createBinaryTypeFrom(binaryType, packageBinding, true);
299 public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, boolean needFieldsAndMethods) {
300 BinaryTypeBinding binaryBinding = new BinaryTypeBinding(packageBinding, binaryType, this);
302 // resolve any array bindings which reference the unresolvedType
303 ReferenceBinding cachedType = packageBinding.getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]);
304 if (cachedType != null) {
305 if (cachedType.isBinaryBinding()) // sanity check before the cast... at this point the cache should ONLY contain unresolved types
306 return (BinaryTypeBinding) cachedType;
308 UnresolvedReferenceBinding unresolvedType = (UnresolvedReferenceBinding) cachedType;
309 unresolvedType.resolvedType = binaryBinding;
310 updateArrayCache(unresolvedType, binaryBinding);
313 packageBinding.addType(binaryBinding);
314 binaryBinding.cachePartsFrom(binaryType, needFieldsAndMethods);
315 return binaryBinding;
317 /* Used to create packages from the package statement.
320 PackageBinding createPackage(char[][] compoundName) {
321 PackageBinding packageBinding = getPackage0(compoundName[0]);
322 if (packageBinding == null || packageBinding == TheNotFoundPackage) {
323 packageBinding = new PackageBinding(compoundName[0], this);
324 knownPackages.put(compoundName[0], packageBinding);
327 for (int i = 1, length = compoundName.length; i < length; i++) {
328 // check to see if it collides with a known type...
329 // this case can only happen if the package does not exist as a directory in the file system
330 // otherwise when the source type was defined, the correct error would have been reported
331 // unless its an unresolved type which is referenced from an inconsistent class file
332 ReferenceBinding type = packageBinding.getType0(compoundName[i]);
333 if (type != null && type != TheNotFoundType && !(type instanceof UnresolvedReferenceBinding))
336 PackageBinding parent = packageBinding;
337 if ((packageBinding = parent.getPackage0(compoundName[i])) == null || packageBinding == TheNotFoundPackage) {
338 // if the package is unknown, check to see if a type exists which would collide with the new package
339 // catches the case of a package statement of: package java.lang.Object;
340 // since the package can be added after a set of source files have already been compiled, we need
341 // whenever a package statement is encountered
342 if (nameEnvironment.findType(compoundName[i], parent.compoundName) != null)
345 packageBinding = new PackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent, this);
346 parent.addPackage(packageBinding);
349 return packageBinding;
351 /* Answer the type for the compoundName if it exists in the cache.
352 * Answer theNotFoundType if it could not be resolved the first time
353 * it was looked up, otherwise answer null.
355 * NOTE: Do not use for nested types... the answer is NOT the same for a.b.C or a.b.C.D.E
356 * assuming C is a type in both cases. In the a.b.C.D.E case, null is the answer.
359 public ReferenceBinding getCachedType(char[][] compoundName) {
360 if (compoundName.length == 1) {
361 if (defaultPackage == null)
363 return defaultPackage.getType0(compoundName[0]);
366 PackageBinding packageBinding = getPackage0(compoundName[0]);
367 if (packageBinding == null || packageBinding == TheNotFoundPackage)
370 for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++)
371 if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null || packageBinding == TheNotFoundPackage)
373 return packageBinding.getType0(compoundName[compoundName.length - 1]);
375 /* Answer the top level package named name if it exists in the cache.
376 * Answer theNotFoundPackage if it could not be resolved the first time
377 * it was looked up, otherwise answer null.
379 * NOTE: Senders must convert theNotFoundPackage into a real problem
380 * package if its to returned.
383 PackageBinding getPackage0(char[] name) {
384 return knownPackages.get(name);
386 /* Answer the top level package named name.
387 * Ask the oracle for the package if its not in the cache.
388 * Answer null if the package cannot be found.
391 PackageBinding getTopLevelPackage(char[] name) {
392 PackageBinding packageBinding = getPackage0(name);
393 if (packageBinding != null) {
394 if (packageBinding == TheNotFoundPackage)
396 return packageBinding;
399 if (nameEnvironment.isPackage(null, name)) {
400 knownPackages.put(name, packageBinding = new PackageBinding(name, this));
401 return packageBinding;
404 knownPackages.put(name, TheNotFoundPackage); // saves asking the oracle next time
407 /* Answer the type corresponding to the compoundName.
408 * Ask the oracle for the type if its not in the cache.
409 * Answer null if the type cannot be found... likely a fatal error.
412 public ReferenceBinding getType(char[][] compoundName) {
413 ReferenceBinding referenceBinding;
415 if (compoundName.length == 1) {
416 if (defaultPackage == null)
419 if ((referenceBinding = defaultPackage.getType0(compoundName[0])) == null) {
420 PackageBinding packageBinding = getPackage0(compoundName[0]);
421 if (packageBinding != null && packageBinding != TheNotFoundPackage)
422 return null; // collides with a known package... should not call this method in such a case
423 referenceBinding = askForType(defaultPackage, compoundName[0]);
426 PackageBinding packageBinding = getPackage0(compoundName[0]);
427 if (packageBinding == TheNotFoundPackage)
430 if (packageBinding != null) {
431 for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) {
432 if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null)
434 if (packageBinding == TheNotFoundPackage)
439 if (packageBinding == null)
440 referenceBinding = askForType(compoundName);
441 else if ((referenceBinding = packageBinding.getType0(compoundName[compoundName.length - 1])) == null)
442 referenceBinding = askForType(packageBinding, compoundName[compoundName.length - 1]);
445 if (referenceBinding == null || referenceBinding == TheNotFoundType)
447 if (referenceBinding instanceof UnresolvedReferenceBinding)
448 referenceBinding = ((UnresolvedReferenceBinding) referenceBinding).resolve(this);
450 // compoundName refers to a nested type incorrectly (for example, package1.A$B)
451 if (referenceBinding.isNestedType())
452 return new ProblemReferenceBinding(compoundName, InternalNameProvided);
453 return referenceBinding;
455 /* Answer the type corresponding to the name from the binary file.
456 * Does not ask the oracle for the type if its not found in the cache... instead an
457 * unresolved type is returned which must be resolved before used.
459 * NOTE: Does NOT answer base types nor array types!
461 * NOTE: Aborts compilation if the class file cannot be found.
464 ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start, int end) {
466 end = signature.length;
468 char[][] compoundName = CharOperation.splitOn('/', signature, start, end);
469 ReferenceBinding binding = getCachedType(compoundName);
470 if (binding == null) {
471 PackageBinding packageBinding = computePackageFrom(compoundName);
472 binding = new UnresolvedReferenceBinding(compoundName, packageBinding);
473 packageBinding.addType(binding);
474 } else if (binding == TheNotFoundType) {
475 problemReporter.isClassPathCorrect(compoundName, null);
476 return null; // will not get here since the above error aborts the compilation
480 /* Answer the type corresponding to the signature from the binary file.
481 * Does not ask the oracle for the type if its not found in the cache... instead an
482 * unresolved type is returned which must be resolved before used.
484 * NOTE: Does answer base types & array types.
486 * NOTE: Aborts compilation if the class file cannot be found.
489 TypeBinding getTypeFromSignature(char[] signature, int start, int end) {
491 while (signature[start] == '[') {
496 end = signature.length - 1;
498 // Just switch on signature[start] - the L case is the else
499 TypeBinding binding = null;
501 switch (signature[start]) {
503 binding = IntBinding;
506 binding = BooleanBinding;
509 binding = VoidBinding;
512 binding = CharBinding;
515 binding = DoubleBinding;
518 binding = ByteBinding;
521 binding = FloatBinding;
524 binding = LongBinding;
527 binding = ShortBinding;
530 throw new Error(Util.bind("error.undefinedBaseType",String.valueOf(signature[start]))); //$NON-NLS-1$
533 binding = getTypeFromConstantPoolName(signature, start + 1, end);
538 return createArrayType(binding, dimension);
540 /* Ask the oracle if a package exists named name in the package named compoundName.
543 boolean isPackage(char[][] compoundName, char[] name) {
544 if (compoundName == null || compoundName.length == 0)
545 return nameEnvironment.isPackage(null, name);
546 return nameEnvironment.isPackage(compoundName, name);
548 // The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready.
550 public MethodVerifier methodVerifier() {
551 if (verifier == null)
552 verifier = new MethodVerifier(this);
555 public void reset() {
556 this.defaultPackage = new PackageBinding(this); // assume the default package always exists
557 this.defaultImports = null;
558 this.knownPackages = new HashtableOfPackage();
560 this.verifier = null;
561 for (int i = this.uniqueArrayBindings.length; --i >= 0;)
562 this.uniqueArrayBindings[i] = null;
563 this.uniqueArrayBindings[0] = new ArrayBinding[50]; // start off the most common 1 dimension array @ 50
565 for (int i = this.units.length; --i >= 0;)
566 this.units[i] = null;
567 this.lastUnitIndex = -1;
568 this.lastCompletedUnitIndex = -1;
569 this.unitBeingCompleted = null; // in case AbortException occurred
571 // name environment has a longer life cycle, and must be reset in
572 // the code which created it.
574 void updateArrayCache(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) {
575 nextDimension : for (int i = 0, length = uniqueArrayBindings.length; i < length; i++) {
576 ArrayBinding[] arrayBindings = uniqueArrayBindings[i];
577 if (arrayBindings != null) {
578 for (int j = 0, max = arrayBindings.length; j < max; j++) {
579 ArrayBinding currentBinding = arrayBindings[j];
580 if (currentBinding == null)
581 continue nextDimension;
582 if (currentBinding.leafComponentType == unresolvedType) {
583 currentBinding.leafComponentType = resolvedType;
584 continue nextDimension;