/******************************************************************************* * Copyright (c) 2000, 2011 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.wst.jsdt.internal.compiler.lookup; import java.util.HashMap; import java.util.Map; import java.util.Stack; import org.eclipse.wst.jsdt.core.compiler.CharOperation; import org.eclipse.wst.jsdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.wst.jsdt.internal.compiler.env.AccessRestriction; import org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit; import org.eclipse.wst.jsdt.internal.compiler.env.INameEnvironment; import org.eclipse.wst.jsdt.internal.compiler.env.ISourceType; import org.eclipse.wst.jsdt.internal.compiler.env.NameEnvironmentAnswer; import org.eclipse.wst.jsdt.internal.compiler.impl.CompilerOptions; import org.eclipse.wst.jsdt.internal.compiler.impl.ITypeRequestor; import org.eclipse.wst.jsdt.internal.compiler.impl.ITypeRequestor2; import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemReporter; import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfPackage; import org.eclipse.wst.jsdt.internal.compiler.util.SimpleSetOfCharArray; import org.eclipse.wst.jsdt.internal.oaametadata.ClassData; import org.eclipse.wst.jsdt.internal.oaametadata.LibraryAPIs; public class LookupEnvironment implements ProblemReasons, TypeConstants { 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 ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(CharOperation.NO_CHAR, null, NotFound); /** * 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; // 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; 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; SimpleSetOfCharArray acceptedCompilationUnits=new SimpleSetOfCharArray(); private boolean fAddingUnits; Stack fAskingForTypeBinding = new Stack(); 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.accessRestrictions = new HashMap(3); } /** * 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 = nameEnvironment.findType(compoundName,this.typeRequestor); if (answer == null) return null; if (answer.isBinaryType()) // the type was found as a .class file typeRequestor.accept(answer.getBinaryType(), computePackageFrom(compoundName), answer.getAccessRestriction()); else if (answer.isCompilationUnit()) { ICompilationUnit compilationUnit = answer.getCompilationUnit(); // if (!acceptedCompilationUnits.includes(compilationUnit.getFileName())) { // the type was found as a .js file, try to build it then search the cache acceptedCompilationUnits.add(compilationUnit.getFileName()); typeRequestor.accept(compilationUnit, answer.getAccessRestriction()); } } else if (answer.isSourceType()) // the type was found as a source model typeRequestor.accept(answer.getSourceTypes(), computePackageFrom(compoundName), answer.getAccessRestriction()); else if (answer.isMetaData()) { LibraryAPIs metadata= answer.getLibraryMetadata(); //if (!acceptedCompilationUnits.includes(metadata.fileName)) //{ // the type was found as a .js file, try to build it then search the cache acceptedCompilationUnits.add(metadata.fileName); typeRequestor.accept(metadata); //} } 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) { return (ReferenceBinding)askForBinding(packageBinding, name, Binding.TYPE|Binding.PACKAGE); } void addUnitsContainingBindings(char[][] types, int kind, String excludePath) { if(fAddingUnits)return; if (types.length == 1 && (kind & Binding.TYPE) > 1 && !fAskingForTypeBinding.isEmpty() && CharOperation.equals(types[0], (char[])fAskingForTypeBinding.peek())) return; fAddingUnits=true; try{ for (int i = 0; i < types.length; i++) { NameEnvironmentAnswer answer = nameEnvironment.findBinding(types[i], defaultPackage.compoundName, kind, this.typeRequestor, true, excludePath); if (answer == null) continue; if (answer.isBinaryType()) // the type was found as a .class file typeRequestor.accept(answer.getBinaryType(), defaultPackage, answer.getAccessRestriction()); else if (answer.isSourceType()) // the type was found as a source model typeRequestor.accept(answer.getSourceTypes(), defaultPackage, answer.getAccessRestriction()); else if (answer.isCompilationUnit()) { ICompilationUnit compilationUnit = answer.getCompilationUnit(); // if (!acceptedCompilationUnits.includes(compilationUnit.getFileName())) { /* the type was found as a .js file, try to build it then search the cache */ acceptedCompilationUnits.add(compilationUnit.getFileName()); if (typeRequestor instanceof ITypeRequestor2) ((ITypeRequestor2) typeRequestor).accept(compilationUnit, types, answer.getAccessRestriction()); else typeRequestor.accept(compilationUnit, answer.getAccessRestriction()); // } } else if (answer.isCompilationUnits()) { ICompilationUnit[] compilationUnits = answer.getCompilationUnits(); for (int j = 0; j < compilationUnits.length; j++) { // if (!acceptedCompilationUnits.includes(compilationUnits[j].getFileName())) { // the type was found as a .js file, try to build it // then search the cache acceptedCompilationUnits.add(compilationUnits[j].getFileName()); // if (compilationUnits[i] instanceof MetadataFile) // typeRequestor.accept(((MetadataFile)compilationUnits[i]).getAPIs()); // else if (typeRequestor instanceof ITypeRequestor2) ((ITypeRequestor2) typeRequestor).accept(compilationUnits[j], types, answer.getAccessRestriction()); else typeRequestor.accept(compilationUnits[j], answer.getAccessRestriction()); // } } } } } finally { fAddingUnits = false; } } void addUnitsContainingBinding(PackageBinding packageBinding, char[] type, int mask, String excludePath) { if (packageBinding == null) { if (defaultPackage == null) return; packageBinding = defaultPackage; } NameEnvironmentAnswer answer = nameEnvironment.findBinding(type, packageBinding.compoundName,mask, this.typeRequestor, true, excludePath); if (answer == null) return; if (answer.isBinaryType()) // the type was found as a .class file typeRequestor.accept(answer.getBinaryType(), packageBinding, answer.getAccessRestriction()); else if (answer.isCompilationUnit()) { ICompilationUnit compilationUnit = answer.getCompilationUnit(); if (!acceptedCompilationUnits.includes(compilationUnit.getFileName())) { // the type was found as a .js file, try to build it then search the cache acceptedCompilationUnits.add(compilationUnit.getFileName()); typeRequestor.accept(compilationUnit, answer.getAccessRestriction()); } }else if (answer.isCompilationUnits()) { ICompilationUnit[] compilationUnits = answer.getCompilationUnits(); for (int i = 0; i < compilationUnits.length; i++) { if (!acceptedCompilationUnits.includes(compilationUnits[i].getFileName())) { // the type was found as a .js file, try to build it then search the cache acceptedCompilationUnits.add(compilationUnits[i].getFileName()); // if (compilationUnits[i] instanceof MetadataFile) // { // typeRequestor.accept(((MetadataFile)compilationUnits[i]).getAPIs()); // } // else typeRequestor.accept(compilationUnits[i], answer .getAccessRestriction()); } } } else if (answer.isSourceType()) // the type was found as a source model typeRequestor.accept(answer.getSourceTypes(), packageBinding, answer.getAccessRestriction()); } Binding askForBinding(GlobalBinding globalBinding, char[] name, int mask) { return null; } Binding askForBinding(PackageBinding packageBinding, char[] name, int mask) { if (packageBinding == null) { if (defaultPackage == null) return null; packageBinding = defaultPackage; } if (mask==Binding.PACKAGE && (name==null || name.length==0)&& this.defaultPackage.compoundName.length==0) return this.defaultPackage; NameEnvironmentAnswer answer = nameEnvironment.findBinding(name, packageBinding.compoundName,mask,this.typeRequestor, true, null); if (answer == null) return null; if((mask & Binding.TYPE) > 1) { if (!fAskingForTypeBinding.isEmpty() && CharOperation.equals(name, (char[]) fAskingForTypeBinding.peek())) return null; fAskingForTypeBinding.push(name); } try { if (answer.isBinaryType()) // the type was found as a .class file typeRequestor.accept(answer.getBinaryType(), packageBinding, answer.getAccessRestriction()); else if (answer.isCompilationUnit()) { ICompilationUnit compilationUnit = answer.getCompilationUnit(); //if (!acceptedCompilationUnits.includes(compilationUnit.getFileName())) // { // the type was found as a .js file, try to build it then search the cache acceptedCompilationUnits.add(compilationUnit.getFileName()); if(!compilationUnit.equals(unitBeingCompleted)) if (typeRequestor instanceof ITypeRequestor2) { ((ITypeRequestor2)typeRequestor).accept(compilationUnit, new char[][]{name}, answer .getAccessRestriction()); } else typeRequestor.accept(compilationUnit, answer.getAccessRestriction()); //} } else if (answer.isCompilationUnits()) { ICompilationUnit[] compilationUnits = answer.getCompilationUnits(); for (int i = 0; i < compilationUnits.length; i++) { //if (!acceptedCompilationUnits.includes(compilationUnits[i].getFileName())) { // the type was found as a .js file, try to build it then search the cache acceptedCompilationUnits.add(compilationUnits[i].getFileName()); if(!compilationUnits[i].equals(unitBeingCompleted)) if (typeRequestor instanceof ITypeRequestor2) { ((ITypeRequestor2)typeRequestor).accept(compilationUnits[i], new char[][]{name}, answer .getAccessRestriction()); } else typeRequestor.accept(compilationUnits[i], answer .getAccessRestriction()); //} } } else if (answer.isSourceType()) // the type was found as a source model typeRequestor.accept(answer.getSourceTypes(), packageBinding, answer.getAccessRestriction()); else if (answer.isMetaData()) { LibraryAPIs metadata= answer.getLibraryMetadata(); // if (!acceptedCompilationUnits.includes(metadata.fileName)) { // the type was found as a .js file, try to build it then search the cache acceptedCompilationUnits.add(metadata.fileName); typeRequestor.accept(metadata); } } } finally { if(mask == Binding.TYPE) { fAskingForTypeBinding.pop(); } } return packageBinding.getBinding0(name,mask); } /* 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) { buildTypeBindings(unit, new char[0][0], accessRestriction); } public void buildTypeBindings(CompilationUnitDeclaration unit, char[][] typeNames, AccessRestriction accessRestriction) { CompilationUnitScope scope = new CompilationUnitScope(unit, this); scope.buildTypeBindings(typeNames, accessRestriction); int unitsLength = units.length; if (++lastUnitIndex >= unitsLength) System.arraycopy(units, 0, units = new CompilationUnitDeclaration[2 * unitsLength], 0, unitsLength); units[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(ISourceType 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(ISourceType 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), needFieldsAndMethods, accessRestriction); return null; // the type already exists & can be retrieved from the cache } public MissingBinaryTypeBinding cacheMissingBinaryType(char[][] compoundName, CompilationUnitDeclaration unit) { PackageBinding packageBinding = computePackageFrom(compoundName); if(unit == null) return null; // create a proxy for the missing BinaryType MissingBinaryTypeBinding type = new MissingBinaryTypeBinding(packageBinding, compoundName, this,unit.scope); if (type.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 = cacheMissingBinaryType(TypeConstants.JAVA_LANG_OBJECT, unit); // create a proxy for the missing Object type type.setMissingSuperclass(objectType); } packageBinding.addType(type); return type; } /* * 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() { stepCompleted = BUILD_TYPE_HIERARCHY; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { (this.unitBeingCompleted = this.units[i]).scope.checkAndSetImports(); } stepCompleted = CHECK_AND_SET_IMPORTS; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { (this.unitBeingCompleted = this.units[i]).scope.connectTypeHierarchy(); } stepCompleted = CONNECT_TYPE_HIERARCHY; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { CompilationUnitScope unitScope = (this.unitBeingCompleted = this.units[i]).scope; unitScope.buildFieldsAndMethods(); this.units[i] = null; // release unnecessary reference to the parsed unit } stepCompleted = BUILD_FIELDS_AND_METHODS; this.lastCompletedUnitIndex = this.lastUnitIndex; this.unitBeingCompleted = null; } public void completeTypeBindings(char[][] types) { stepCompleted = BUILD_TYPE_HIERARCHY; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { (this.unitBeingCompleted = this.units[i]).scope.checkAndSetImports(); } stepCompleted = CHECK_AND_SET_IMPORTS; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { (this.unitBeingCompleted = this.units[i]).scope.connectTypeHierarchy(types); } stepCompleted = CONNECT_TYPE_HIERARCHY; for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) { CompilationUnitScope unitScope = (this.unitBeingCompleted = this.units[i]).scope; unitScope.buildFieldsAndMethods(); this.units[i] = null; // release unnecessary reference to the parsed unit } 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 */ /* * 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) { completeTypeBindings(parsedUnit, new char[0][0]); } public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, char[][] typeNames) { if (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 (stepCompleted >= CHECK_AND_SET_IMPORTS) (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports(); if (stepCompleted >= CONNECT_TYPE_HIERARCHY) (this.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy(typeNames); 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 */ public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, char[][] typeNames, boolean buildFieldsAndMethods) { if (parsedUnit.scope == null) return; // parsing errors were too severe (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports(); parsedUnit.scope.connectTypeHierarchy(typeNames); if (buildFieldsAndMethods) parsedUnit.scope.buildFieldsAndMethods(); this.unitBeingCompleted = null; } public void completeTypeBindings(CompilationUnitDeclaration parsedUnit, boolean buildFieldsAndMethods) { completeTypeBindings(parsedUnit, new char[0][0], buildFieldsAndMethods); } public TypeBinding computeBoxingType(TypeBinding type) { TypeBinding boxedType; switch (type.id) { case TypeIds.T_JavaLangBoolean : return TypeBinding.BOOLEAN; 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_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); } return type; } private PackageBinding computePackageFrom(char[][] constantPoolName) { return defaultPackage; // if (constantPoolName.length == 1) // return defaultPackage; // // PackageBinding packageBinding = getPackage0(constantPoolName[0]); // if (packageBinding == null || packageBinding == TheNotFoundPackage) { // packageBinding = new PackageBinding(constantPoolName[0], 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); // parent.addPackage(packageBinding); // } // } // return packageBinding; } /* 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 = uniqueArrayBindings.length; ArrayBinding[] arrayBindings; if (dimIndex < length) { if ((arrayBindings = uniqueArrayBindings[dimIndex]) == null) uniqueArrayBindings[dimIndex] = arrayBindings = new ArrayBinding[10]; } else { System.arraycopy( uniqueArrayBindings, 0, uniqueArrayBindings = new ArrayBinding[dimensionCount][], 0, length); 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); uniqueArrayBindings[dimIndex] = arrayBindings; return arrayBindings[length] = new ArrayBinding(leafComponentType, dimensionCount, this); } public BinaryTypeBinding createBinaryTypeFrom(ISourceType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) { return createBinaryTypeFrom(binaryType, packageBinding, true, accessRestriction); } public BinaryTypeBinding createBinaryTypeFrom(ISourceType 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 packages from the package statement. */ public PackageBinding createPackage(char[][] compoundName) { PackageBinding packageBinding = getPackage0(compoundName[0]); if (packageBinding == null) { packageBinding = new PackageBinding(compoundName[0], 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) { // 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 (nameEnvironment.findType(compoundName[i], parent.compoundName,this.typeRequestor) != null) // return null; packageBinding = new PackageBinding(CharOperation.subarray(compoundName, 0, i + 1), parent, this); parent.addPackage(packageBinding); } } return packageBinding; } /** * 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 (defaultPackage == null) return null; return defaultPackage.getType0(compoundName[0]); } PackageBinding packageBinding = getPackage0(compoundName[0]); if (packageBinding == null) return null; for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null) 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) { if (CharOperation.equals(name, defaultPackage.readableName())) return defaultPackage; return 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 return cacheMissingBinaryType( compoundName, scope == null ? this.unitBeingCompleted : scope.referenceCompilationUnit()); } /* 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) { if (CharOperation.equals(name, defaultPackage.readableName())) return defaultPackage; // return null; //} PackageBinding packageBinding = getPackage0(name); if (packageBinding != null) { return packageBinding; } if (nameEnvironment.isPackage(null, name)) { knownPackages.put(name, packageBinding = new PackageBinding(name, this)); return packageBinding; } 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 (defaultPackage == null) return null; if ((referenceBinding = defaultPackage.getType0(compoundName[0])) == null) { PackageBinding packageBinding = getPackage0(compoundName[0]); if (packageBinding != null) return null; // collides with a known package... should not call this method in such a case referenceBinding = askForType(defaultPackage, compoundName[0]); } } else { PackageBinding packageBinding = getPackage0(compoundName[0]); if (packageBinding != null) { for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) { if ((packageBinding = packageBinding.getPackage0(compoundName[i])) == null) break; } } 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 = 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; } /* 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! */ ReferenceBinding getTypeFromCompoundName(char[][] compoundName, boolean isParameterized) { ReferenceBinding binding = getCachedType(compoundName); if (binding == null) { PackageBinding packageBinding = computePackageFrom(compoundName); binding = new UnresolvedReferenceBinding(compoundName, packageBinding); packageBinding.addType(binding); } else if (binding == TheNotFoundType) { // create a proxy for the missing BinaryType binding = cacheMissingBinaryType(compoundName, this.unitBeingCompleted); } 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) { if (end == -1) end = signature.length; char[][] compoundName = CharOperation.splitOn('/', signature, start, end); return getTypeFromCompoundName(compoundName, isParameterized); } /* 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) { 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 'F' : binding = TypeBinding.FLOAT; break; case 'J' : binding = TypeBinding.LONG; break; case 'S' : binding = TypeBinding.SHORT; break; default : problemReporter.corruptedSignature(enclosingType, signature, start); // will never reach here, since error will cause abort } } else { binding = getTypeFromConstantPoolName(signature, start + 1, end, isParameterized); // skip leading 'L' or 'T' } if (dimension == 0) return binding; return createArrayType(binding, dimension); } TypeBinding getTypeFromTypeSignature(SignatureWrapper wrapper, ReferenceBinding enclosingType) { // 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') { return null; // cannot reach this, since previous problem will abort compilation } TypeBinding type = getTypeFromSignature(wrapper.signature, wrapper.start, wrapper.computeEnd(), false, enclosingType); return dimension == 0 ? type : createArrayType(type, dimension); } TypeBinding getTypeFromVariantTypeSignature( SignatureWrapper wrapper, ReferenceBinding enclosingType, ReferenceBinding genericType, int rank) { // VariantTypeSignature = '-' TypeSignature // or '+' TypeSignature // or TypeSignature // or '*' switch (wrapper.signature[wrapper.start]) { case '-' : // ? super aType wrapper.start++; TypeBinding bound = getTypeFromTypeSignature(wrapper, enclosingType); case '+' : // ? extends aType wrapper.start++; bound = getTypeFromTypeSignature(wrapper, enclosingType); case '*' : // ? wrapper.start++; default : return getTypeFromTypeSignature(wrapper, enclosingType); } } /* 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 nameEnvironment.isPackage(null, name); return nameEnvironment.isPackage(compoundName, name); } // The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready. public MethodVerifier methodVerifier() { if (verifier == null) verifier = new MethodVerifier(this); return verifier; } 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; } 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 // name environment has a longer life cycle, and must be reset in // the code which created it. this.acceptedCompilationUnits.clear(); this.fAskingForTypeBinding.clear(); } /** * 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); } public void buildTypeBindings(LibraryAPIs libraryMetaData) { ClassData[] classes = libraryMetaData.classes; PackageBinding packageBinding = this.defaultPackage; int typeLength=(classes!=null ? classes.length:0); int count = 0; LibraryAPIsScope scope=new LibraryAPIsScope(libraryMetaData,this); SourceTypeBinding[] topLevelTypes = new SourceTypeBinding[typeLength]; for (int i = 0; i < typeLength; i++) { ClassData clazz=classes[i]; char[][] className = CharOperation.arrayConcat(packageBinding.compoundName,clazz.name.toCharArray()); SourceTypeBinding binding = new MetatdataTypeBinding(className, packageBinding, clazz, scope) ; this.defaultPackage.addType(binding); binding.fPackage.addType(binding); topLevelTypes[count++] = binding; } if (count != topLevelTypes.length) System.arraycopy(topLevelTypes, 0, topLevelTypes = new SourceTypeBinding[count], 0, count); char [] fullFileName=libraryMetaData.fileName; LibraryAPIsBinding libraryAPIsBinding=new LibraryAPIsBinding(null,defaultPackage,fullFileName); if (packageBinding!=this.defaultPackage) packageBinding.addBinding(libraryAPIsBinding, libraryAPIsBinding.shortReadableName(), Binding.COMPILATION_UNIT); } }