/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.lookup; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.internal.compiler.util.HashtableOfPackage; import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType; public class PackageBinding extends Binding implements TypeConstants { public char[][] compoundName; PackageBinding parent; LookupEnvironment environment; HashtableOfType knownTypes; HashtableOfPackage knownPackages; protected PackageBinding() { } public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnvironment environment) { this.compoundName = compoundName; this.parent = parent; this.environment = environment; this.knownTypes = null; // initialized if used... class counts can be // very large 300-600 this.knownPackages = new HashtableOfPackage(3); // sub-package counts // are typically 0-3 } public PackageBinding(char[] topLevelPackageName, LookupEnvironment environment) { this(new char[][] { topLevelPackageName }, null, environment); } /* * Create the default package. */ public PackageBinding(LookupEnvironment environment) { this(CharOperation.NO_CHAR_CHAR, null, environment); } private void addNotFoundPackage(char[] simpleName) { knownPackages.put(simpleName, LookupEnvironment.TheNotFoundPackage); } private void addNotFoundType(char[] simpleName) { if (knownTypes == null) knownTypes = new HashtableOfType(25); knownTypes.put(simpleName, LookupEnvironment.TheNotFoundType); } void addPackage(PackageBinding element) { knownPackages.put( element.compoundName[element.compoundName.length - 1], element); } void addType(ReferenceBinding element) { if (knownTypes == null) knownTypes = new HashtableOfType(25); knownTypes.put(element.compoundName[element.compoundName.length - 1], element); } /* * API Answer the receiver's binding type from Binding.BindingID. */ public final int bindingType() { return PACKAGE; } private PackageBinding findPackage(char[] name) { if (!environment.isPackage(this.compoundName, name)) return null; char[][] compoundName = CharOperation.arrayConcat(this.compoundName, name); PackageBinding newPackageBinding = new PackageBinding(compoundName, this, environment); addPackage(newPackageBinding); return newPackageBinding; } /* * Answer the subpackage named name; ask the oracle for the package if its * not in the cache. Answer null if it could not be resolved. * * NOTE: This should only be used when we know there is NOT a type with the * same name. */ PackageBinding getPackage(char[] name) { PackageBinding binding = getPackage0(name); if (binding != null) { if (binding == LookupEnvironment.TheNotFoundPackage) return null; else return binding; } if ((binding = findPackage(name)) != null) return binding; // not found so remember a problem package binding in the cache for // future lookups addNotFoundPackage(name); return null; } /* * Answer the subpackage 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 knownPackages.get(name); } /* * Answer the type named name; ask the oracle for the type if its not in the * cache. Answer a NotVisible problem type if the type is not visible from * the invocationPackage. Answer null if it could not be resolved. * * NOTE: This should only be used by source types/scopes which know there is * NOT a package with the same name. */ ReferenceBinding getType(char[] name) { ReferenceBinding binding = getType0(name); if (binding == null) { if ((binding = environment.askForType(this, name)) == null) { // not found so remember a problem type binding in the cache for // future lookups addNotFoundType(name); return null; } } if (binding == LookupEnvironment.TheNotFoundType) return null; if (binding instanceof UnresolvedReferenceBinding) binding = ((UnresolvedReferenceBinding) binding) .resolve(environment); if (binding.isNestedType()) return new ProblemReferenceBinding(name, InternalNameProvided); return binding; } /* * Answer the type named name 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: Senders must convert theNotFoundType into a real problem reference * type if its to returned. */ ReferenceBinding getType0(char[] name) { if (knownTypes == null) return null; return knownTypes.get(name); } /* * Answer the package or type named name; ask the oracle if it is not in the * cache. Answer null if it could not be resolved. * * When collisions exist between a type name & a package name, answer the * package. Treat the type as if it does not exist... a problem was already * reported when the type was defined. * * NOTE: no visibility checks are performed. THIS SHOULD ONLY BE USED BY * SOURCE TYPES/SCOPES. */ public Binding getTypeOrPackage(char[] name) { PackageBinding packageBinding = getPackage0(name); if (packageBinding != null && packageBinding != LookupEnvironment.TheNotFoundPackage) return packageBinding; ReferenceBinding typeBinding = getType0(name); if (typeBinding != null && typeBinding != LookupEnvironment.TheNotFoundType) { if (typeBinding instanceof UnresolvedReferenceBinding) typeBinding = ((UnresolvedReferenceBinding) typeBinding) .resolve(environment); if (typeBinding.isNestedType()) return new ProblemReferenceBinding(name, InternalNameProvided); return typeBinding; } // always look for the name as a sub-package if its not a known type if (packageBinding == null && (packageBinding = findPackage(name)) != null) return packageBinding; if (typeBinding == null) { // if no package was found, find the type named name relative to the // receiver if ((typeBinding = environment.askForType(this, name)) != null) { if (typeBinding.isNestedType()) return new ProblemReferenceBinding(name, InternalNameProvided); return typeBinding; } // Since name could not be found, add problem bindings // to the collections so it will be reported as an error next time. addNotFoundPackage(name); addNotFoundType(name); } else { if (packageBinding == LookupEnvironment.TheNotFoundPackage) packageBinding = null; if (typeBinding == LookupEnvironment.TheNotFoundType) typeBinding = null; } if (packageBinding != null) return packageBinding; else return typeBinding; } public char[] readableName() /* java.lang */{ return CharOperation.concatWith(compoundName, '.'); } public String toString() { if (compoundName == CharOperation.NO_CHAR_CHAR) return "The Default Package"; //$NON-NLS-1$ else return "package " + ((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED"); //$NON-NLS-1$ //$NON-NLS-2$ } }