/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ClassFilePool; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.IBinaryType; import org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.eclipse.jdt.internal.compiler.util.HashtableOfPackage; import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; public class LookupEnvironment implements ProblemReasons, TypeConstants { /** * Map from typeBinding -> accessRestriction rule */ private Map accessRestrictions; ImportBinding[] defaultImports; public PackageBinding defaultPackage; HashtableOfPackage knownPackages; private int lastCompletedUnitIndex= -1; private int lastUnitIndex= -1; public INameEnvironment nameEnvironment; public CompilerOptions globalOptions; public ProblemReporter problemReporter; public ClassFilePool classFilePool; // indicate in which step on the compilation we are. // step 1 : build the reference binding // step 2 : conect the hierarchy (connect bindings) // step 3 : build fields and method bindings. private int stepCompleted; public ITypeRequestor typeRequestor; private ArrayBinding[][] uniqueArrayBindings; private SimpleLookupTable uniqueParameterizedTypeBindings; private SimpleLookupTable uniqueRawTypeBindings; private SimpleLookupTable uniqueWildcardBindings; private SimpleLookupTable uniqueParameterizedGenericMethodBindings; private SimpleLookupTable uniqueGetClassMethodBinding; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=300734 public CompilationUnitDeclaration unitBeingCompleted= null; // only set while completing units public Object missingClassFileLocation= null; // only set when resolving certain references, to help locating problems private CompilationUnitDeclaration[] units= new CompilationUnitDeclaration[4]; private MethodVerifier verifier; public MethodBinding arrayClone; private ArrayList missingTypes; public boolean isProcessingAnnotations= false; final static int BUILD_FIELDS_AND_METHODS= 4; final static int BUILD_TYPE_HIERARCHY= 1; final static int CHECK_AND_SET_IMPORTS= 2; final static int CONNECT_TYPE_HIERARCHY= 3; static final ProblemPackageBinding TheNotFoundPackage= new ProblemPackageBinding(CharOperation.NO_CHAR, NotFound); static final ProblemReferenceBinding TheNotFoundType= new ProblemReferenceBinding(CharOperation.NO_CHAR_CHAR, null, NotFound); public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions globalOptions, ProblemReporter problemReporter, INameEnvironment nameEnvironment) { this.typeRequestor= typeRequestor; this.globalOptions= globalOptions; this.problemReporter= problemReporter; this.defaultPackage= new PackageBinding(this); // assume the default package always exists this.defaultImports= null; this.nameEnvironment= nameEnvironment; this.knownPackages= new HashtableOfPackage(); this.uniqueArrayBindings= new ArrayBinding[5][]; this.uniqueArrayBindings[0]= new ArrayBinding[50]; // start off the most common 1 dimension array @ 50 this.uniqueParameterizedTypeBindings= new SimpleLookupTable(3); this.uniqueRawTypeBindings= new SimpleLookupTable(3); this.uniqueWildcardBindings= new SimpleLookupTable(3); this.uniqueParameterizedGenericMethodBindings= new SimpleLookupTable(3); this.missingTypes= null; this.accessRestrictions= new HashMap(3); this.classFilePool= ClassFilePool.newInstance(); } /** * Ask the name environment for a type which corresponds to the compoundName. Answer null if the * name cannot be found. */ public ReferenceBinding askForType(char[][] compoundName) { NameEnvironmentAnswer answer= this.nameEnvironment.findType(compoundName); if (answer == null) return null; if (answer.isBinaryType()) { // the type was found as a .class file this.typeRequestor.accept(answer.getBinaryType(), computePackageFrom(compoundName, false /* valid pkg */), answer.getAccessRestriction()); } else if (answer.isCompilationUnit()) { // the type was found as a .java file, try to build it then search the cache this.typeRequestor.accept(answer.getCompilationUnit(), answer.getAccessRestriction()); } else if (answer.isSourceType()) { // the type was found as a source model this.typeRequestor.accept(answer.getSourceTypes(), computePackageFrom(compoundName, false /* valid pkg */), answer.getAccessRestriction()); } return getCachedType(compoundName); } /* Ask the oracle for a type named name in the packageBinding. * Answer null if the name cannot be found. */ ReferenceBinding askForType(PackageBinding packageBinding, char[] name) { if (packageBinding == null) { if (this.defaultPackage == null) return null; packageBinding= this.defaultPackage; } NameEnvironmentAnswer answer= this.nameEnvironment.findType(name, packageBinding.compoundName); if (answer == null) return null; if (answer.isBinaryType()) { // the type was found as a .class file this.typeRequestor.accept(answer.getBinaryType(), packageBinding, answer.getAccessRestriction()); } else if (answer.isCompilationUnit()) { // the type was found as a .java file, try to build it then search the cache this.typeRequestor.accept(answer.getCompilationUnit(), answer.getAccessRestriction()); } else if (answer.isSourceType()) { // the type was found as a source model this.typeRequestor.accept(answer.getSourceTypes(), packageBinding, answer.getAccessRestriction()); } return packageBinding.getType0(name); } /* Create the initial type bindings for the compilation unit. * * See completeTypeBindings() for a description of the remaining steps * * NOTE: This method can be called multiple times as additional source files are needed */ public void buildTypeBindings(CompilationUnitDeclaration unit, AccessRestriction accessRestriction) { CompilationUnitScope scope= new CompilationUnitScope(unit, this); scope.buildTypeBindings(accessRestriction); int unitsLength= this.units.length; if (++this.lastUnitIndex >= unitsLength) System.arraycopy(this.units, 0, this.units= new CompilationUnitDeclaration[2 * unitsLength], 0, unitsLength); this.units[this.lastUnitIndex]= unit; } /* Cache the binary type since we know it is needed during this compile. * * Answer the created BinaryTypeBinding or null if the type is already in the cache. */ public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType, AccessRestriction accessRestriction) { return cacheBinaryType(binaryType, true, accessRestriction); } /* Cache the binary type since we know it is needed during this compile. * * Answer the created BinaryTypeBinding or null if the type is already in the cache. */ public BinaryTypeBinding cacheBinaryType(IBinaryType binaryType, boolean needFieldsAndMethods, AccessRestriction accessRestriction) { char[][] compoundName= CharOperation.splitOn('/', binaryType.getName()); ReferenceBinding existingType= getCachedType(compoundName); if (existingType == null || existingType instanceof UnresolvedReferenceBinding) // only add the binary type if its not already in the cache return createBinaryTypeFrom(binaryType, computePackageFrom(compoundName, false /* valid pkg */), needFieldsAndMethods, accessRestriction); return null; // the type already exists & can be retrieved from the cache } public void completeTypeBindings() { this.stepCompleted= BUILD_TYPE_HIERARCHY; for (int i= this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { (this.unitBeingCompleted= this.units[i]).scope.checkAndSetImports(); } this.stepCompleted= CHECK_AND_SET_IMPORTS; for (int i= this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { (this.unitBeingCompleted= this.units[i]).scope.connectTypeHierarchy(); } this.stepCompleted= CONNECT_TYPE_HIERARCHY; for (int i= this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { CompilationUnitScope unitScope= (this.unitBeingCompleted= this.units[i]).scope; unitScope.checkParameterizedTypes(); unitScope.buildFieldsAndMethods(); this.units[i]= null; // release unnecessary reference to the parsed unit } this.stepCompleted= BUILD_FIELDS_AND_METHODS; this.lastCompletedUnitIndex= this.lastUnitIndex; this.unitBeingCompleted= null; } /* * 1. Connect the type hierarchy for the type bindings created for parsedUnits. * 2. Create the field bindings * 3. Create the method bindings */ /* We know each known compilationUnit is free of errors at this point... * * Each step will create additional bindings unless a problem is detected, in which * case either the faulty import/superinterface/field/method will be skipped or a * suitable replacement will be substituted (such as Object for a missing superclass) */ public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) { if (this.stepCompleted == BUILD_FIELDS_AND_METHODS) { // This can only happen because the original set of units are completely built and // are now being processed, so we want to treat all the additional units as a group // until they too are completely processed. completeTypeBindings(); } else { if (parsedUnit.scope == null) return; // parsing errors were too severe if (this.stepCompleted >= CHECK_AND_SET_IMPORTS) (this.unitBeingCompleted= parsedUnit).scope.checkAndSetImports(); if (this.stepCompleted >= CONNECT_TYPE_HIERARCHY) (this.unitBeingCompleted= parsedUnit).scope.connectTypeHierarchy(); this.unitBeingCompleted= null; } } /* * Used by other compiler tools which do not start by calling completeTypeBindings(). * * 1. Connect the type hierarchy for the type bindings created for parsedUnits. * 2. Create the field bindings * 3. Create the method bindings */ /* * Each step will create additional bindings unless a problem is detected, in which * case either the faulty import/superinterface/field/method will be skipped or a * suitable replacement will be substituted (such as Object for a missing superclass) */ public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, boolean buildFieldsAndMethods) { if (parsedUnit.scope == null) return; // parsing errors were too severe (this.unitBeingCompleted= parsedUnit).scope.checkAndSetImports(); parsedUnit.scope.connectTypeHierarchy(); parsedUnit.scope.checkParameterizedTypes(); if (buildFieldsAndMethods) parsedUnit.scope.buildFieldsAndMethods(); this.unitBeingCompleted= null; } /* * Used by other compiler tools which do not start by calling completeTypeBindings() * and have more than 1 unit to complete. * * 1. Connect the type hierarchy for the type bindings created for parsedUnits. * 2. Create the field bindings * 3. Create the method bindings */ public void completeTypeBindings(CompilationUnitDeclaration[] parsedUnits, boolean[] buildFieldsAndMethods, int unitCount) { for (int i= 0; i < unitCount; i++) { CompilationUnitDeclaration parsedUnit= parsedUnits[i]; if (parsedUnit.scope != null) (this.unitBeingCompleted= parsedUnit).scope.checkAndSetImports(); } for (int i= 0; i < unitCount; i++) { CompilationUnitDeclaration parsedUnit= parsedUnits[i]; if (parsedUnit.scope != null) (this.unitBeingCompleted= parsedUnit).scope.connectTypeHierarchy(); } for (int i= 0; i < unitCount; i++) { CompilationUnitDeclaration parsedUnit= parsedUnits[i]; if (parsedUnit.scope != null) { (this.unitBeingCompleted= parsedUnit).scope.checkParameterizedTypes(); if (buildFieldsAndMethods[i]) parsedUnit.scope.buildFieldsAndMethods(); } } this.unitBeingCompleted= null; } public MethodBinding computeArrayClone(MethodBinding objectClone) { if (this.arrayClone == null) { this.arrayClone= new MethodBinding( (objectClone.modifiers & ~ClassFileConstants.AccProtected) | ClassFileConstants.AccPublic, TypeConstants.CLONE, objectClone.returnType, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, // no exception for array specific method (ReferenceBinding)objectClone.returnType); } return this.arrayClone; } public TypeBinding computeBoxingType(TypeBinding type) { TypeBinding boxedType; switch (type.id) { case TypeIds.T_JavaLangBoolean: return TypeBinding.BOOLEAN; case TypeIds.T_JavaLangByte: return TypeBinding.BYTE; case TypeIds.T_JavaLangCharacter: return TypeBinding.CHAR; case TypeIds.T_JavaLangShort: return TypeBinding.SHORT; case TypeIds.T_JavaLangDouble: return TypeBinding.DOUBLE; case TypeIds.T_JavaLangFloat: return TypeBinding.FLOAT; case TypeIds.T_JavaLangInteger: return TypeBinding.INT; case TypeIds.T_JavaLangLong: return TypeBinding.LONG; case TypeIds.T_int: boxedType= getType(JAVA_LANG_INTEGER); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_INTEGER, null, NotFound); case TypeIds.T_byte: boxedType= getType(JAVA_LANG_BYTE); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_BYTE, null, NotFound); case TypeIds.T_short: boxedType= getType(JAVA_LANG_SHORT); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_SHORT, null, NotFound); case TypeIds.T_char: boxedType= getType(JAVA_LANG_CHARACTER); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_CHARACTER, null, NotFound); case TypeIds.T_long: boxedType= getType(JAVA_LANG_LONG); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_LONG, null, NotFound); case TypeIds.T_float: boxedType= getType(JAVA_LANG_FLOAT); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_FLOAT, null, NotFound); case TypeIds.T_double: boxedType= getType(JAVA_LANG_DOUBLE); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_DOUBLE, null, NotFound); case TypeIds.T_boolean: boxedType= getType(JAVA_LANG_BOOLEAN); if (boxedType != null) return boxedType; return new ProblemReferenceBinding(JAVA_LANG_BOOLEAN, null, NotFound); // case TypeIds.T_int : // return getResolvedType(JAVA_LANG_INTEGER, null); // case TypeIds.T_byte : // return getResolvedType(JAVA_LANG_BYTE, null); // case TypeIds.T_short : // return getResolvedType(JAVA_LANG_SHORT, null); // case TypeIds.T_char : // return getResolvedType(JAVA_LANG_CHARACTER, null); // case TypeIds.T_long : // return getResolvedType(JAVA_LANG_LONG, null); // case TypeIds.T_float : // return getResolvedType(JAVA_LANG_FLOAT, null); // case TypeIds.T_double : // return getResolvedType(JAVA_LANG_DOUBLE, null); // case TypeIds.T_boolean : // return getResolvedType(JAVA_LANG_BOOLEAN, null); } // allow indirect unboxing conversion for wildcards and type parameters switch (type.kind()) { case Binding.WILDCARD_TYPE: case Binding.INTERSECTION_TYPE: case Binding.TYPE_PARAMETER: switch (type.erasure().id) { case TypeIds.T_JavaLangBoolean: return TypeBinding.BOOLEAN; case TypeIds.T_JavaLangByte: return TypeBinding.BYTE; case TypeIds.T_JavaLangCharacter: return TypeBinding.CHAR; case TypeIds.T_JavaLangShort: return TypeBinding.SHORT; case TypeIds.T_JavaLangDouble: return TypeBinding.DOUBLE; case TypeIds.T_JavaLangFloat: return TypeBinding.FLOAT; case TypeIds.T_JavaLangInteger: return TypeBinding.INT; case TypeIds.T_JavaLangLong: return TypeBinding.LONG; } } return type; } private PackageBinding computePackageFrom(char[][] constantPoolName, boolean isMissing) { if (constantPoolName.length == 1) return this.defaultPackage; PackageBinding packageBinding= getPackage0(constantPoolName[0]); if (packageBinding == null || packageBinding == TheNotFoundPackage) { packageBinding= new PackageBinding(constantPoolName[0], this); if (isMissing) packageBinding.tagBits|= TagBits.HasMissingType; this.knownPackages.put(constantPoolName[0], packageBinding); } for (int i= 1, length= constantPoolName.length - 1; i < length; i++) { PackageBinding parent= packageBinding; if ((packageBinding= parent.getPackage0(constantPoolName[i])) == null || packageBinding == TheNotFoundPackage) { packageBinding= new PackageBinding(CharOperation.subarray(constantPoolName, 0, i + 1), parent, this); if (isMissing) { packageBinding.tagBits|= TagBits.HasMissingType; } parent.addPackage(packageBinding); } } return packageBinding; } /** * Convert a given source type into a parameterized form if generic. generic X<E> --> param X<E> */ public ReferenceBinding convertToParameterizedType(ReferenceBinding originalType) { if (originalType != null) { boolean isGeneric= originalType.isGenericType(); ReferenceBinding originalEnclosingType= originalType.enclosingType(); ReferenceBinding convertedEnclosingType= originalEnclosingType; boolean needToConvert= isGeneric; if (originalEnclosingType != null) { convertedEnclosingType= originalType.isStatic() ? (ReferenceBinding)convertToRawType(originalEnclosingType, false /*do not force conversion of enclosing types*/) : convertToParameterizedType(originalEnclosingType); needToConvert|= originalEnclosingType != convertedEnclosingType; } if (needToConvert) { return createParameterizedType(originalType, isGeneric ? originalType.typeVariables() : null, convertedEnclosingType); } } return originalType; } /** * Returns the given binding's raw type binding. * * @param type the TypeBinding to raw convert * @param forceRawEnclosingType forces recursive raw conversion of enclosing types (used in * Javadoc references only) * @return TypeBinding the raw converted TypeBinding */ public TypeBinding convertToRawType(TypeBinding type, boolean forceRawEnclosingType) { int dimension; TypeBinding originalType; switch (type.kind()) { case Binding.BASE_TYPE: case Binding.TYPE_PARAMETER: case Binding.WILDCARD_TYPE: case Binding.INTERSECTION_TYPE: case Binding.RAW_TYPE: return type; case Binding.ARRAY_TYPE: dimension= type.dimensions(); originalType= type.leafComponentType(); break; default: if (type.id == TypeIds.T_JavaLangObject) return type; // Object is not generic dimension= 0; originalType= type; } boolean needToConvert; switch (originalType.kind()) { case Binding.BASE_TYPE: return type; case Binding.GENERIC_TYPE: needToConvert= true; break; case Binding.PARAMETERIZED_TYPE: ParameterizedTypeBinding paramType= (ParameterizedTypeBinding)originalType; needToConvert= paramType.genericType().isGenericType(); // only recursive call to enclosing type can find parameterizedType with arguments break; default: needToConvert= false; break; } ReferenceBinding originalEnclosing= originalType.enclosingType(); TypeBinding convertedType; if (originalEnclosing == null) { convertedType= needToConvert ? createRawType((ReferenceBinding)originalType.erasure(), null) : originalType; } else { ReferenceBinding convertedEnclosing; if (originalEnclosing.kind() == Binding.RAW_TYPE) { needToConvert|= !((ReferenceBinding)originalType).isStatic(); convertedEnclosing= originalEnclosing; } else if (forceRawEnclosingType && !needToConvert/*stop recursion when conversion occurs*/) { convertedEnclosing= (ReferenceBinding)convertToRawType(originalEnclosing, forceRawEnclosingType); needToConvert= originalEnclosing != convertedEnclosing; // only convert generic or parameterized types } else if (needToConvert || ((ReferenceBinding)originalType).isStatic()) { convertedEnclosing= (ReferenceBinding)convertToRawType(originalEnclosing, false); } else { convertedEnclosing= convertToParameterizedType(originalEnclosing); } if (needToConvert) { convertedType= createRawType((ReferenceBinding)originalType.erasure(), convertedEnclosing); } else if (originalEnclosing != convertedEnclosing) { convertedType= createParameterizedType((ReferenceBinding)originalType.erasure(), null, convertedEnclosing); } else { convertedType= originalType; } } if (originalType != convertedType) { return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType; } return type; } /** * Convert an array of types in raw forms. Only allocate an array if anything is different. */ public ReferenceBinding[] convertToRawTypes(ReferenceBinding[] originalTypes, boolean forceErasure, boolean forceRawEnclosingType) { if (originalTypes == null) return null; ReferenceBinding[] convertedTypes= originalTypes; for (int i= 0, length= originalTypes.length; i < length; i++) { ReferenceBinding originalType= originalTypes[i]; ReferenceBinding convertedType= (ReferenceBinding)convertToRawType(forceErasure ? originalType.erasure() : originalType, forceRawEnclosingType); if (convertedType != originalType) { if (convertedTypes == originalTypes) { System.arraycopy(originalTypes, 0, convertedTypes= new ReferenceBinding[length], 0, i); } convertedTypes[i]= convertedType; } else if (convertedTypes != originalTypes) { convertedTypes[i]= originalType; } } return convertedTypes; } // variation for unresolved types in binaries (consider generic type as raw) public TypeBinding convertUnresolvedBinaryToRawType(TypeBinding type) { int dimension; TypeBinding originalType; switch (type.kind()) { case Binding.BASE_TYPE: case Binding.TYPE_PARAMETER: case Binding.WILDCARD_TYPE: case Binding.INTERSECTION_TYPE: case Binding.RAW_TYPE: return type; case Binding.ARRAY_TYPE: dimension= type.dimensions(); originalType= type.leafComponentType(); break; default: if (type.id == TypeIds.T_JavaLangObject) return type; // Object is not generic dimension= 0; originalType= type; } boolean needToConvert; switch (originalType.kind()) { case Binding.BASE_TYPE: return type; case Binding.GENERIC_TYPE: needToConvert= true; break; case Binding.PARAMETERIZED_TYPE: ParameterizedTypeBinding paramType= (ParameterizedTypeBinding)originalType; needToConvert= paramType.genericType().isGenericType(); // only recursive call to enclosing type can find parameterizedType with arguments break; default: needToConvert= false; break; } ReferenceBinding originalEnclosing= originalType.enclosingType(); TypeBinding convertedType; if (originalEnclosing == null) { convertedType= needToConvert ? createRawType((ReferenceBinding)originalType.erasure(), null) : originalType; } else { ReferenceBinding convertedEnclosing= (ReferenceBinding)convertUnresolvedBinaryToRawType(originalEnclosing); if (convertedEnclosing != originalEnclosing) { needToConvert|= !((ReferenceBinding)originalType).isStatic(); } if (needToConvert) { convertedType= createRawType((ReferenceBinding)originalType.erasure(), convertedEnclosing); } else if (originalEnclosing != convertedEnclosing) { convertedType= createParameterizedType((ReferenceBinding)originalType.erasure(), null, convertedEnclosing); } else { convertedType= originalType; } } if (originalType != convertedType) { return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType; } return type; } /* * Used to guarantee annotation identity. */ public AnnotationBinding createAnnotation(ReferenceBinding annotationType, ElementValuePair[] pairs) { if (pairs.length != 0) { AnnotationBinding.setMethodBindings(annotationType, pairs); } return new AnnotationBinding(annotationType, pairs); } /* * Used to guarantee array type identity. */ public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount) { if (leafComponentType instanceof LocalTypeBinding) // cache local type arrays with the local type itself return ((LocalTypeBinding)leafComponentType).createArrayType(dimensionCount, this); // find the array binding cache for this dimension int dimIndex= dimensionCount - 1; int length= this.uniqueArrayBindings.length; ArrayBinding[] arrayBindings; if (dimIndex < length) { if ((arrayBindings= this.uniqueArrayBindings[dimIndex]) == null) this.uniqueArrayBindings[dimIndex]= arrayBindings= new ArrayBinding[10]; } else { System.arraycopy( this.uniqueArrayBindings, 0, this.uniqueArrayBindings= new ArrayBinding[dimensionCount][], 0, length); this.uniqueArrayBindings[dimIndex]= arrayBindings= new ArrayBinding[10]; } // find the cached array binding for this leaf component type (if any) int index= -1; length= arrayBindings.length; while (++index < length) { ArrayBinding currentBinding= arrayBindings[index]; if (currentBinding == null) // no matching array, but space left return arrayBindings[index]= new ArrayBinding(leafComponentType, dimensionCount, this); if (currentBinding.leafComponentType == leafComponentType) return currentBinding; } // no matching array, no space left System.arraycopy( arrayBindings, 0, (arrayBindings= new ArrayBinding[length * 2]), 0, length); this.uniqueArrayBindings[dimIndex]= arrayBindings; return arrayBindings[length]= new ArrayBinding(leafComponentType, dimensionCount, this); } public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) { return createBinaryTypeFrom(binaryType, packageBinding, true, accessRestriction); } public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, boolean needFieldsAndMethods, AccessRestriction accessRestriction) { BinaryTypeBinding binaryBinding= new BinaryTypeBinding(packageBinding, binaryType, this); // resolve any array bindings which reference the unresolvedType ReferenceBinding cachedType= packageBinding.getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]); if (cachedType != null) { // update reference to unresolved binding after having read classfile (knows whether generic for raw conversion) if (cachedType instanceof UnresolvedReferenceBinding) { ((UnresolvedReferenceBinding)cachedType).setResolvedType(binaryBinding, this); } else { if (cachedType.isBinaryBinding()) // sanity check... at this point the cache should ONLY contain unresolved types return (BinaryTypeBinding)cachedType; // it is possible with a large number of source files (exceeding AbstractImageBuilder.MAX_AT_ONCE) that a member type can be in the cache as an UnresolvedType, // but because its enclosingType is resolved while its created (call to BinaryTypeBinding constructor), its replaced with a source type return null; } } packageBinding.addType(binaryBinding); setAccessRestriction(binaryBinding, accessRestriction); binaryBinding.cachePartsFrom(binaryType, needFieldsAndMethods); return binaryBinding; } /* * Used to create types denoting missing types. * If package is given, then reuse the package; if not then infer a package from compound name. * If the package is existing, then install the missing type in type cache */ public MissingTypeBinding createMissingType(PackageBinding packageBinding, char[][] compoundName) { // create a proxy for the missing BinaryType if (packageBinding == null) { packageBinding= computePackageFrom(compoundName, true /* missing */); if (packageBinding == TheNotFoundPackage) packageBinding= this.defaultPackage; } MissingTypeBinding missingType= new MissingTypeBinding(packageBinding, compoundName, this); if (missingType.id != TypeIds.T_JavaLangObject) { // make Object be its superclass - it could in turn be missing as well ReferenceBinding objectType= getType(TypeConstants.JAVA_LANG_OBJECT); if (objectType == null) { objectType= createMissingType(null, TypeConstants.JAVA_LANG_OBJECT); // create a proxy for the missing Object type } missingType.setMissingSuperclass(objectType); } packageBinding.addType(missingType); if (this.missingTypes == null) this.missingTypes= new ArrayList(3); this.missingTypes.add(missingType); return missingType; } /* * 1. Connect the type hierarchy for the type bindings created for parsedUnits. * 2. Create the field bindings * 3. Create the method bindings */ public PackageBinding createPackage(char[][] compoundName) { PackageBinding packageBinding= getPackage0(compoundName[0]); if (packageBinding == null || packageBinding == TheNotFoundPackage) { packageBinding= new PackageBinding(compoundName[0], this); this.knownPackages.put(compoundName[0], packageBinding); } for (int i= 1, length= compoundName.length; i < length; i++) { // check to see if it collides with a known type... // this case can only happen if the package does not exist as a directory in the file system // otherwise when the source type was defined, the correct error would have been reported // unless its an unresolved type which is referenced from an inconsistent class file // NOTE: empty packages are not packages according to changes in JLS v2, 7.4.3 // so not all types cause collision errors when they're created even though the package did exist ReferenceBinding type= packageBinding.getType0(compoundName[i]); if (type != null && type != TheNotFoundType && !(type instanceof UnresolvedReferenceBinding)) return null; PackageBinding parent= packageBinding; if ((packageBinding= parent.getPackage0(compoundName[i])) == null || packageBinding == TheNotFoundPackage) { // if the package is unknown, check to see if a type exists which would collide with the new package // catches the case of a package statement of: package java.lang.Object; // since the package can be added after a set of source files have already been compiled, // we need to check whenever a package is created if (this.nameEnvironment.findType(compoundName[i], parent.compoundName) != null) return null; packageBinding= new PackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent, this); parent.addPackage(packageBinding); } } return packageBinding; } public ParameterizedGenericMethodBinding createParameterizedGenericMethod(MethodBinding genericMethod, RawTypeBinding rawType) { // cached info is array of already created parameterized types for this type ParameterizedGenericMethodBinding[] cachedInfo= (ParameterizedGenericMethodBinding[])this.uniqueParameterizedGenericMethodBindings.get(genericMethod); boolean needToGrow= false; int index= 0; if (cachedInfo != null) { nextCachedMethod: // iterate existing parameterized for reusing one with same type arguments if any for (int max= cachedInfo.length; index < max; index++) { ParameterizedGenericMethodBinding cachedMethod= cachedInfo[index]; if (cachedMethod == null) break nextCachedMethod; if (!cachedMethod.isRaw) continue nextCachedMethod; if (cachedMethod.declaringClass != (rawType == null ? genericMethod.declaringClass : rawType)) continue nextCachedMethod; return cachedMethod; } needToGrow= true; } else { cachedInfo= new ParameterizedGenericMethodBinding[5]; this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo); } // grow cache ? int length= cachedInfo.length; if (needToGrow && index == length) { System.arraycopy(cachedInfo, 0, cachedInfo= new ParameterizedGenericMethodBinding[length * 2], 0, length); this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo); } // add new binding ParameterizedGenericMethodBinding parameterizedGenericMethod= new ParameterizedGenericMethodBinding(genericMethod, rawType, this); cachedInfo[index]= parameterizedGenericMethod; return parameterizedGenericMethod; } public ParameterizedGenericMethodBinding createParameterizedGenericMethod(MethodBinding genericMethod, TypeBinding[] typeArguments) { // cached info is array of already created parameterized types for this type ParameterizedGenericMethodBinding[] cachedInfo= (ParameterizedGenericMethodBinding[])this.uniqueParameterizedGenericMethodBindings.get(genericMethod); int argLength= typeArguments == null ? 0 : typeArguments.length; boolean needToGrow= false; int index= 0; if (cachedInfo != null) { nextCachedMethod: // iterate existing parameterized for reusing one with same type arguments if any for (int max= cachedInfo.length; index < max; index++) { ParameterizedGenericMethodBinding cachedMethod= cachedInfo[index]; if (cachedMethod == null) break nextCachedMethod; if (cachedMethod.isRaw) continue nextCachedMethod; TypeBinding[] cachedArguments= cachedMethod.typeArguments; int cachedArgLength= cachedArguments == null ? 0 : cachedArguments.length; if (argLength != cachedArgLength) continue nextCachedMethod; for (int j= 0; j < cachedArgLength; j++) { if (typeArguments[j] != cachedArguments[j]) continue nextCachedMethod; } // all arguments match, reuse current return cachedMethod; } needToGrow= true; } else { cachedInfo= new ParameterizedGenericMethodBinding[5]; this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo); } // grow cache ? int length= cachedInfo.length; if (needToGrow && index == length) { System.arraycopy(cachedInfo, 0, cachedInfo= new ParameterizedGenericMethodBinding[length * 2], 0, length); this.uniqueParameterizedGenericMethodBindings.put(genericMethod, cachedInfo); } // add new binding ParameterizedGenericMethodBinding parameterizedGenericMethod= new ParameterizedGenericMethodBinding(genericMethod, typeArguments, this); cachedInfo[index]= parameterizedGenericMethod; return parameterizedGenericMethod; } public ParameterizedMethodBinding createGetClassMethod(TypeBinding receiverType, MethodBinding originalMethod, Scope scope) { // see if we have already cached this method for the given receiver type. ParameterizedMethodBinding retVal= null; if (this.uniqueGetClassMethodBinding == null) { this.uniqueGetClassMethodBinding= new SimpleLookupTable(3); } else { retVal= (ParameterizedMethodBinding)this.uniqueGetClassMethodBinding.get(receiverType); } if (retVal == null) { retVal= ParameterizedMethodBinding.instantiateGetClass(receiverType, originalMethod, scope); this.uniqueGetClassMethodBinding.put(receiverType, retVal); } return retVal; } public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) { // cached info is array of already created parameterized types for this type ParameterizedTypeBinding[] cachedInfo= (ParameterizedTypeBinding[])this.uniqueParameterizedTypeBindings.get(genericType); int argLength= typeArguments == null ? 0 : typeArguments.length; boolean needToGrow= false; int index= 0; if (cachedInfo != null) { nextCachedType: // iterate existing parameterized for reusing one with same type arguments if any for (int max= cachedInfo.length; index < max; index++) { ParameterizedTypeBinding cachedType= cachedInfo[index]; if (cachedType == null) break nextCachedType; if (cachedType.actualType() != genericType) continue nextCachedType; // remain of unresolved type if (cachedType.enclosingType() != enclosingType) continue nextCachedType; TypeBinding[] cachedArguments= cachedType.arguments; int cachedArgLength= cachedArguments == null ? 0 : cachedArguments.length; if (argLength != cachedArgLength) continue nextCachedType; // would be an error situation (from unresolved binaries) for (int j= 0; j < cachedArgLength; j++) { if (typeArguments[j] != cachedArguments[j]) continue nextCachedType; } // all arguments match, reuse current return cachedType; } needToGrow= true; } else { cachedInfo= new ParameterizedTypeBinding[5]; this.uniqueParameterizedTypeBindings.put(genericType, cachedInfo); } // grow cache ? int length= cachedInfo.length; if (needToGrow && index == length) { System.arraycopy(cachedInfo, 0, cachedInfo= new ParameterizedTypeBinding[length * 2], 0, length); this.uniqueParameterizedTypeBindings.put(genericType, cachedInfo); } // add new binding ParameterizedTypeBinding parameterizedType= new ParameterizedTypeBinding(genericType, typeArguments, enclosingType, this); cachedInfo[index]= parameterizedType; return parameterizedType; } public RawTypeBinding createRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) { // cached info is array of already created raw types for this type RawTypeBinding[] cachedInfo= (RawTypeBinding[])this.uniqueRawTypeBindings.get(genericType); boolean needToGrow= false; int index= 0; if (cachedInfo != null) { nextCachedType: // iterate existing parameterized for reusing one with same type arguments if any for (int max= cachedInfo.length; index < max; index++) { RawTypeBinding cachedType= cachedInfo[index]; if (cachedType == null) break nextCachedType; if (cachedType.actualType() != genericType) continue nextCachedType; // remain of unresolved type if (cachedType.enclosingType() != enclosingType) continue nextCachedType; // all enclosing type match, reuse current return cachedType; } needToGrow= true; } else { cachedInfo= new RawTypeBinding[1]; this.uniqueRawTypeBindings.put(genericType, cachedInfo); } // grow cache ? int length= cachedInfo.length; if (needToGrow && index == length) { System.arraycopy(cachedInfo, 0, cachedInfo= new RawTypeBinding[length * 2], 0, length); this.uniqueRawTypeBindings.put(genericType, cachedInfo); } // add new binding RawTypeBinding rawType= new RawTypeBinding(genericType, enclosingType, this); cachedInfo[index]= rawType; return rawType; } public WildcardBinding createWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) { // cached info is array of already created wildcard types for this type if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation genericType= ReferenceBinding.LUB_GENERIC; WildcardBinding[] cachedInfo= (WildcardBinding[])this.uniqueWildcardBindings.get(genericType); boolean needToGrow= false; int index= 0; if (cachedInfo != null) { nextCachedType: // iterate existing wildcards for reusing one with same information if any for (int max= cachedInfo.length; index < max; index++) { WildcardBinding cachedType= cachedInfo[index]; if (cachedType == null) break nextCachedType; if (cachedType.genericType != genericType) continue nextCachedType; // remain of unresolved type if (cachedType.rank != rank) continue nextCachedType; if (cachedType.boundKind != boundKind) continue nextCachedType; if (cachedType.bound != bound) continue nextCachedType; if (cachedType.otherBounds != otherBounds) { int cachedLength= cachedType.otherBounds == null ? 0 : cachedType.otherBounds.length; int length= otherBounds == null ? 0 : otherBounds.length; if (cachedLength != length) continue nextCachedType; for (int j= 0; j < length; j++) { if (cachedType.otherBounds[j] != otherBounds[j]) continue nextCachedType; } } // all match, reuse current return cachedType; } needToGrow= true; } else { cachedInfo= new WildcardBinding[10]; this.uniqueWildcardBindings.put(genericType, cachedInfo); } // grow cache ? int length= cachedInfo.length; if (needToGrow && index == length) { System.arraycopy(cachedInfo, 0, cachedInfo= new WildcardBinding[length * 2], 0, length); this.uniqueWildcardBindings.put(genericType, cachedInfo); } // add new binding WildcardBinding wildcard= new WildcardBinding(genericType, rank, bound, otherBounds, boundKind, this); cachedInfo[index]= wildcard; return wildcard; } /** * Returns the access restriction associated to a given type, or null if none */ public AccessRestriction getAccessRestriction(TypeBinding type) { return (AccessRestriction)this.accessRestrictions.get(type); } /** * Answer the type for the compoundName if it exists in the cache. Answer theNotFoundType if it * could not be resolved the first time it was looked up, otherwise answer null. * * NOTE: Do not use for nested types... the answer is NOT the same for a.b.C or a.b.C.D.E * assuming C is a type in both cases. In the a.b.C.D.E case, null is the answer. */ public ReferenceBinding getCachedType(char[][] compoundName) { if (compoundName.length == 1) { if (this.defaultPackage == null) return null; return this.defaultPackage.getType0(compoundName[0]); } PackageBinding packageBinding= getPackage0(compoundName[0]); if (packageBinding == null || packageBinding == TheNotFoundPackage) return null; for (int i= 1, packageLength= compoundName.length - 1; i < packageLength; i++) if ((packageBinding= packageBinding.getPackage0(compoundName[i])) == null || packageBinding == TheNotFoundPackage) return null; return packageBinding.getType0(compoundName[compoundName.length - 1]); } /* Answer the top level package named name if it exists in the cache. * Answer theNotFoundPackage if it could not be resolved the first time * it was looked up, otherwise answer null. * * NOTE: Senders must convert theNotFoundPackage into a real problem * package if its to returned. */ PackageBinding getPackage0(char[] name) { return this.knownPackages.get(name); } /* Answer the type corresponding to the compoundName. * Ask the name environment for the type if its not in the cache. * Fail with a classpath error if the type cannot be found. */ public ReferenceBinding getResolvedType(char[][] compoundName, Scope scope) { ReferenceBinding type= getType(compoundName); if (type != null) return type; // create a proxy for the missing BinaryType // report the missing class file first this.problemReporter.isClassPathCorrect( compoundName, scope == null ? this.unitBeingCompleted : scope.referenceCompilationUnit(), this.missingClassFileLocation); return createMissingType(null, compoundName); } /* Answer the top level package named name. * Ask the oracle for the package if its not in the cache. * Answer null if the package cannot be found. */ PackageBinding getTopLevelPackage(char[] name) { PackageBinding packageBinding= getPackage0(name); if (packageBinding != null) { if (packageBinding == TheNotFoundPackage) return null; return packageBinding; } if (this.nameEnvironment.isPackage(null, name)) { this.knownPackages.put(name, packageBinding= new PackageBinding(name, this)); return packageBinding; } this.knownPackages.put(name, TheNotFoundPackage); // saves asking the oracle next time return null; } /* Answer the type corresponding to the compoundName. * Ask the name environment for the type if its not in the cache. * Answer null if the type cannot be found. */ public ReferenceBinding getType(char[][] compoundName) { ReferenceBinding referenceBinding; if (compoundName.length == 1) { if (this.defaultPackage == null) return null; if ((referenceBinding= this.defaultPackage.getType0(compoundName[0])) == null) { PackageBinding packageBinding= getPackage0(compoundName[0]); if (packageBinding != null && packageBinding != TheNotFoundPackage) return null; // collides with a known package... should not call this method in such a case referenceBinding= askForType(this.defaultPackage, compoundName[0]); } } else { PackageBinding packageBinding= getPackage0(compoundName[0]); if (packageBinding == TheNotFoundPackage) return null; if (packageBinding != null) { for (int i= 1, packageLength= compoundName.length - 1; i < packageLength; i++) { if ((packageBinding= packageBinding.getPackage0(compoundName[i])) == null) break; if (packageBinding == TheNotFoundPackage) return null; } } if (packageBinding == null) referenceBinding= askForType(compoundName); else if ((referenceBinding= packageBinding.getType0(compoundName[compoundName.length - 1])) == null) referenceBinding= askForType(packageBinding, compoundName[compoundName.length - 1]); } if (referenceBinding == null || referenceBinding == TheNotFoundType) return null; referenceBinding= (ReferenceBinding)BinaryTypeBinding.resolveType(referenceBinding, this, false /* no raw conversion for now */); // compoundName refers to a nested type incorrectly (for example, package1.A$B) if (referenceBinding.isNestedType()) return new ProblemReferenceBinding(compoundName, referenceBinding, InternalNameProvided); return referenceBinding; } private TypeBinding[] getTypeArgumentsFromSignature(SignatureWrapper wrapper, TypeVariableBinding[] staticVariables, ReferenceBinding enclosingType, ReferenceBinding genericType, char[][][] missingTypeNames) { java.util.ArrayList args= new java.util.ArrayList(2); int rank= 0; do { args.add(getTypeFromVariantTypeSignature(wrapper, staticVariables, enclosingType, genericType, rank++, missingTypeNames)); } while (wrapper.signature[wrapper.start] != '>'); wrapper.start++; // skip '>' TypeBinding[] typeArguments= new TypeBinding[args.size()]; args.toArray(typeArguments); return typeArguments; } /* Answer the type corresponding to the compound name. * Does not ask the oracle for the type if its not found in the cache... instead an * unresolved type is returned which must be resolved before used. * * NOTE: Does NOT answer base types nor array types! */ private ReferenceBinding getTypeFromCompoundName(char[][] compoundName, boolean isParameterized, boolean wasMissingType) { ReferenceBinding binding= getCachedType(compoundName); if (binding == null) { PackageBinding packageBinding= computePackageFrom(compoundName, false /* valid pkg */); binding= new UnresolvedReferenceBinding(compoundName, packageBinding); if (wasMissingType) { binding.tagBits|= TagBits.HasMissingType; // record it was bound to a missing type } packageBinding.addType(binding); } else if (binding == TheNotFoundType) { // report the missing class file first this.problemReporter.isClassPathCorrect(compoundName, this.unitBeingCompleted, this.missingClassFileLocation); // create a proxy for the missing BinaryType binding= createMissingType(null, compoundName); } else if (!isParameterized) { // check raw type, only for resolved types binding= (ReferenceBinding)convertUnresolvedBinaryToRawType(binding); } return binding; } /* Answer the type corresponding to the name from the binary file. * Does not ask the oracle for the type if its not found in the cache... instead an * unresolved type is returned which must be resolved before used. * * NOTE: Does NOT answer base types nor array types! */ ReferenceBinding getTypeFromConstantPoolName(char[] signature, int start, int end, boolean isParameterized, char[][][] missingTypeNames) { if (end == -1) end= signature.length; char[][] compoundName= CharOperation.splitOn('/', signature, start, end); boolean wasMissingType= false; if (missingTypeNames != null) { for (int i= 0, max= missingTypeNames.length; i < max; i++) { if (CharOperation.equals(compoundName, missingTypeNames[i])) { wasMissingType= true; break; } } } return getTypeFromCompoundName(compoundName, isParameterized, wasMissingType); } /* Answer the type corresponding to the signature from the binary file. * Does not ask the oracle for the type if its not found in the cache... instead an * unresolved type is returned which must be resolved before used. * * NOTE: Does answer base types & array types. */ TypeBinding getTypeFromSignature(char[] signature, int start, int end, boolean isParameterized, TypeBinding enclosingType, char[][][] missingTypeNames) { int dimension= 0; while (signature[start] == '[') { start++; dimension++; } if (end == -1) end= signature.length - 1; // Just switch on signature[start] - the L case is the else TypeBinding binding= null; if (start == end) { switch (signature[start]) { case 'I': binding= TypeBinding.INT; break; case 'Z': binding= TypeBinding.BOOLEAN; break; case 'V': binding= TypeBinding.VOID; break; case 'C': binding= TypeBinding.CHAR; break; case 'D': binding= TypeBinding.DOUBLE; break; case 'B': binding= TypeBinding.BYTE; break; case 'F': binding= TypeBinding.FLOAT; break; case 'J': binding= TypeBinding.LONG; break; case 'S': binding= TypeBinding.SHORT; break; default: this.problemReporter.corruptedSignature(enclosingType, signature, start); // will never reach here, since error will cause abort } } else { binding= getTypeFromConstantPoolName(signature, start + 1, end, isParameterized, missingTypeNames); // skip leading 'L' or 'T' } if (dimension == 0) return binding; return createArrayType(binding, dimension); } public TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, TypeVariableBinding[] staticVariables, ReferenceBinding enclosingType, char[][][] missingTypeNames) { // TypeVariableSignature = 'T' Identifier ';' // ArrayTypeSignature = '[' TypeSignature // ClassTypeSignature = 'L' Identifier TypeArgs(optional) ';' // or ClassTypeSignature '.' 'L' Identifier TypeArgs(optional) ';' // TypeArgs = '<' VariantTypeSignature VariantTypeSignatures '>' int dimension= 0; while (wrapper.signature[wrapper.start] == '[') { wrapper.start++; dimension++; } if (wrapper.signature[wrapper.start] == 'T') { int varStart= wrapper.start + 1; int varEnd= wrapper.computeEnd(); for (int i= staticVariables.length; --i >= 0;) if (CharOperation.equals(staticVariables[i].sourceName, wrapper.signature, varStart, varEnd)) return dimension == 0 ? (TypeBinding)staticVariables[i] : createArrayType(staticVariables[i], dimension); ReferenceBinding initialType= enclosingType; do { TypeVariableBinding[] enclosingTypeVariables; if (enclosingType instanceof BinaryTypeBinding) { // compiler normal case, no eager resolution of binary variables enclosingTypeVariables= ((BinaryTypeBinding)enclosingType).typeVariables; // do not trigger resolution of variables } else { // codepath only use by codeassist for decoding signatures enclosingTypeVariables= enclosingType.typeVariables(); } for (int i= enclosingTypeVariables.length; --i >= 0;) if (CharOperation.equals(enclosingTypeVariables[i].sourceName, wrapper.signature, varStart, varEnd)) return dimension == 0 ? (TypeBinding)enclosingTypeVariables[i] : createArrayType(enclosingTypeVariables[i], dimension); } while ((enclosingType= enclosingType.enclosingType()) != null); this.problemReporter.undefinedTypeVariableSignature(CharOperation.subarray(wrapper.signature, varStart, varEnd), initialType); return null; // cannot reach this, since previous problem will abort compilation } boolean isParameterized; TypeBinding type= getTypeFromSignature(wrapper.signature, wrapper.start, wrapper.computeEnd(), isParameterized= (wrapper.end == wrapper.bracket), enclosingType, missingTypeNames); if (!isParameterized) return dimension == 0 ? type : createArrayType(type, dimension); // type must be a ReferenceBinding at this point, cannot be a BaseTypeBinding or ArrayTypeBinding ReferenceBinding actualType= (ReferenceBinding)type; if (actualType instanceof UnresolvedReferenceBinding) if (CharOperation.indexOf('$', actualType.compoundName[actualType.compoundName.length - 1]) > 0) actualType= (ReferenceBinding)BinaryTypeBinding.resolveType(actualType, this, false /* no raw conversion */); // must resolve member types before asking for enclosingType ReferenceBinding actualEnclosing= actualType.enclosingType(); if (actualEnclosing != null) { // convert needed if read some static member type actualEnclosing= (ReferenceBinding)convertToRawType(actualEnclosing, false /*do not force conversion of enclosing types*/); } TypeBinding[] typeArguments= getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, actualType, missingTypeNames); ParameterizedTypeBinding parameterizedType= createParameterizedType(actualType, typeArguments, actualEnclosing); while (wrapper.signature[wrapper.start] == '.') { wrapper.start++; // skip '.' int memberStart= wrapper.start; char[] memberName= wrapper.nextWord(); BinaryTypeBinding.resolveType(parameterizedType, this, false); ReferenceBinding memberType= parameterizedType.genericType().getMemberType(memberName); // need to protect against the member type being null when the signature is invalid if (memberType == null) this.problemReporter.corruptedSignature(parameterizedType, wrapper.signature, memberStart); // aborts if (wrapper.signature[wrapper.start] == '<') { wrapper.start++; // skip '<' typeArguments= getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, memberType, missingTypeNames); } else { typeArguments= null; } parameterizedType= createParameterizedType(memberType, typeArguments, parameterizedType); } wrapper.start++; // skip ';' return dimension == 0 ? (TypeBinding)parameterizedType : createArrayType(parameterizedType, dimension); } TypeBinding getTypeFromVariantTypeSignature( SignatureWrapper wrapper, TypeVariableBinding[] staticVariables, ReferenceBinding enclosingType, ReferenceBinding genericType, int rank, char[][][] missingTypeNames) { // VariantTypeSignature = '-' TypeSignature // or '+' TypeSignature // or TypeSignature // or '*' switch (wrapper.signature[wrapper.start]) { case '-': // ? super aType wrapper.start++; TypeBinding bound= getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames); return createWildcard(genericType, rank, bound, null /*no extra bound*/, Wildcard.SUPER); case '+': // ? extends aType wrapper.start++; bound= getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames); return createWildcard(genericType, rank, bound, null /*no extra bound*/, Wildcard.EXTENDS); case '*': // ? wrapper.start++; return createWildcard(genericType, rank, null, null /*no extra bound*/, Wildcard.UNBOUND); default: return getTypeFromTypeSignature(wrapper, staticVariables, enclosingType, missingTypeNames); } } boolean isMissingType(char[] typeName) { for (int i= this.missingTypes == null ? 0 : this.missingTypes.size(); --i >= 0;) { MissingTypeBinding missingType= (MissingTypeBinding)this.missingTypes.get(i); if (CharOperation.equals(missingType.sourceName, typeName)) return true; } return false; } /* Ask the oracle if a package exists named name in the package named compoundName. */ boolean isPackage(char[][] compoundName, char[] name) { if (compoundName == null || compoundName.length == 0) return this.nameEnvironment.isPackage(null, name); return this.nameEnvironment.isPackage(compoundName, name); } // The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready. public MethodVerifier methodVerifier() { if (this.verifier == null) this.verifier= newMethodVerifier(); return this.verifier; } public MethodVerifier newMethodVerifier() { return this.globalOptions.sourceLevel < ClassFileConstants.JDK1_5 ? new MethodVerifier(this) : new MethodVerifier15(this); // covariance only if sourceLevel is >= 1.5 } public void releaseClassFiles(org.eclipse.jdt.internal.compiler.ClassFile[] classFiles) { for (int i= 0, fileCount= classFiles.length; i < fileCount; i++) this.classFilePool.release(classFiles[i]); } public void reset() { this.defaultPackage= new PackageBinding(this); // assume the default package always exists this.defaultImports= null; this.knownPackages= new HashtableOfPackage(); this.accessRestrictions= new HashMap(3); this.verifier= null; for (int i= this.uniqueArrayBindings.length; --i >= 0;) { ArrayBinding[] arrayBindings= this.uniqueArrayBindings[i]; if (arrayBindings != null) for (int j= arrayBindings.length; --j >= 0;) arrayBindings[j]= null; } // NOTE: remember to fix #updateCaches(...) when adding unique binding caches this.uniqueParameterizedTypeBindings= new SimpleLookupTable(3); this.uniqueRawTypeBindings= new SimpleLookupTable(3); this.uniqueWildcardBindings= new SimpleLookupTable(3); this.uniqueParameterizedGenericMethodBindings= new SimpleLookupTable(3); this.uniqueGetClassMethodBinding= null; this.missingTypes= null; for (int i= this.units.length; --i >= 0;) this.units[i]= null; this.lastUnitIndex= -1; this.lastCompletedUnitIndex= -1; this.unitBeingCompleted= null; // in case AbortException occurred this.classFilePool.reset(); // name environment has a longer life cycle, and must be reset in // the code which created it. } /** * Associate a given type with some access restriction (did not store the restriction directly * into binding, since sparse information) */ public void setAccessRestriction(ReferenceBinding type, AccessRestriction accessRestriction) { if (accessRestriction == null) return; type.modifiers|= ExtraCompilerModifiers.AccRestrictedAccess; this.accessRestrictions.put(type, accessRestriction); } void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) { // walk all the unique collections & replace the unresolvedType with the resolvedType // must prevent 2 entries so == still works (1 containing the unresolvedType and the other containing the resolvedType) if (this.uniqueParameterizedTypeBindings.get(unresolvedType) != null) { // update the key Object[] keys= this.uniqueParameterizedTypeBindings.keyTable; for (int i= 0, l= keys.length; i < l; i++) { if (keys[i] == unresolvedType) { keys[i]= resolvedType; // hashCode is based on compoundName so this works - cannot be raw since type of parameterized type break; } } } if (this.uniqueRawTypeBindings.get(unresolvedType) != null) { // update the key Object[] keys= this.uniqueRawTypeBindings.keyTable; for (int i= 0, l= keys.length; i < l; i++) { if (keys[i] == unresolvedType) { keys[i]= resolvedType; // hashCode is based on compoundName so this works break; } } } if (this.uniqueWildcardBindings.get(unresolvedType) != null) { // update the key Object[] keys= this.uniqueWildcardBindings.keyTable; for (int i= 0, l= keys.length; i < l; i++) { if (keys[i] == unresolvedType) { keys[i]= resolvedType; // hashCode is based on compoundName so this works break; } } } } }