Move BindingKey out of dom package
diff --git a/dom/org/eclipse/jdt/core/dom/BindingKey.java b/dom/org/eclipse/jdt/core/dom/BindingKey.java
deleted file mode 100644
index 113c7f7..0000000
--- a/dom/org/eclipse/jdt/core/dom/BindingKey.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2004 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 org.eclipse.jdt.core.dom;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.Wildcard;
-import org.eclipse.jdt.internal.compiler.lookup.BaseTypes;
-import org.eclipse.jdt.internal.compiler.lookup.Binding;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
-import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
-import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
-import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
-import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
-import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
-import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
-import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
-import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
-
-/**
- * Internal class.
- * @since 3.1
- */
-class BindingKey {
-	 char[][] compoundName;
-	 int dimension;
-	 BindingKeyScanner scanner;
-	 CompilationUnitResolver resolver;
-	 LookupEnvironment environment;
-	 
-	 BindingKey(String key, CompilationUnitResolver resolver) {
-	 	this.scanner = new BindingKeyScanner(key.toCharArray());
-	 	this.resolver = resolver;
-	 	this.environment = resolver.lookupEnvironment;
-	 	reset();
-	 }
-	 
-	 /*
-	  * If not already cached, computes and cache the compound name (pkg name + top level name) of this key.
-	  * Returns the package name if key is a pkg key.
-	  * Returns an empty array if malformed.
-	  * This key's scanner should be positioned on the package or type token.
-	  */
-	 char[][] compoundName() {
-	 	if (this.compoundName == null) {
-	 		switch(this.scanner.nextToken()) {
-	 			case BindingKeyScanner.PACKAGE:
-	 			case BindingKeyScanner.TYPE:
-		 			this.compoundName = CharOperation.splitOn('/', this.scanner.getTokenSource());
-		 			break;
-		 		case BindingKeyScanner.ARRAY:
-		 			this.dimension = this.scanner.getTokenSource().length;
-		 			if (this.scanner.nextToken() == BindingKeyScanner.TYPE)
-			 			this.compoundName = CharOperation.splitOn('/', this.scanner.getTokenSource());
-		 			else
-		 				// malformed key
-				 		this.compoundName = CharOperation.NO_CHAR_CHAR;
-		 			break;
-		 		default:
-			 		// malformed key
-			 		this.compoundName = CharOperation.NO_CHAR_CHAR;
-		 			break;
-	 		}
-	 	}
-	 	return this.compoundName;
-	 }
-	 
-	 /*
-	  * If the given dimension is greater than 0 returns an array binding for the given type binding.
-	  * Otherwise return the given type binding.
-	  * Returns null if the given type binding is null.
-	  */
-	 TypeBinding getArrayBinding(int dim, TypeBinding binding) {
-	 	if (binding == null) return null;
-	 	if (dim == 0) return binding;
-		return this.environment.createArrayType(binding, dim);
-	}
-	
-	TypeBinding getBaseTypeBinding(char[] signature) {
-		switch (signature[0]) {
-			case 'I' :
-				return BaseTypes.IntBinding;
-			case 'Z' :
-				return BaseTypes.BooleanBinding;
-			case 'V' :
-				return BaseTypes.VoidBinding;
-			case 'C' :
-				return BaseTypes.CharBinding;
-			case 'D' :
-				return BaseTypes.DoubleBinding;
-			case 'B' :
-				return BaseTypes.ByteBinding;
-			case 'F' :
-				return BaseTypes.FloatBinding;
-			case 'J' :
-				return BaseTypes.LongBinding;
-			case 'S' :
-				return BaseTypes.ShortBinding;
-			default :
-				return null;
-		}
-	}
-	 
-	/*
-	 * Returns a binary binding corresonding to this key's compound name.
-	 * Returns null if not found.
-	 * This key's scanner should be positioned on the token after the top level type.
-	 */
-	TypeBinding getBinaryBinding() {
-		TypeBinding binding = this.environment.getType(this.compoundName);
-		return getArrayBinding(this.dimension, binding);
-	}
-	 
-	 /*
-	  * Finds the compilation unit declaration corresponding to the key in the given lookup environment.
-	  * Returns null if no compilation unit declaration could be found.
-	  * This key's scanner should be positioned on the package token.
-	  */
-	 CompilationUnitDeclaration getCompilationUnitDeclaration() {
-		char[][] name = compoundName();
-		if (name.length == 0) return null;
-		ReferenceBinding binding = this.environment.getType(name);
-		if (!(binding instanceof SourceTypeBinding)) return null;
-		return ((SourceTypeBinding) binding).scope.compilationUnitScope().referenceContext;
-	 }
-	 
-	  Binding getCompilerBinding(CompilationUnitDeclaration parsedUnit) {
-	 	switch (this.scanner.token) {
-	 		case BindingKeyScanner.PACKAGE:
-	 			return new PackageBinding(this.compoundName, null, this.environment);
-	 		case BindingKeyScanner.TYPE:
-	 			if (this.compoundName.length == 1 && this.compoundName[0].length == 1) {
-	 				// case of base type
-		 			TypeBinding baseTypeBinding = getBaseTypeBinding(this.compoundName[0]);
-		 			if (baseTypeBinding != null) 
-	 					return getArrayBinding(this.dimension, baseTypeBinding);
-	 			}
-	 			char[] typeName = this.compoundName[this.compoundName.length-1];
-	 			int dim = this.dimension;
-	 			TypeBinding binding = parsedUnit == null ? getBinaryBinding() : getTypeBinding(parsedUnit, parsedUnit.types, typeName);
-	 			if (binding == null) return null;
-				TypeBinding typeBinding = null;
-				if (this.scanner.isAtParametersStart()) {
-					if (this.scanner.isAtTypeParameterStart())	 					
-	 					// generic type binding
-	 					typeBinding = getGenericTypeBinding((SourceTypeBinding) binding);
-	 				else if (this.scanner.isAtTypeStart() || this.scanner.isAtWildCardStart())
-						// parameterized type binding
-	 					typeBinding = getParameterizedTypeBinding((ReferenceBinding) binding, null/*no enclosing type*/); 
-				} else if (binding.typeVariables().length > 0)
-					// raw type binding
-					typeBinding = this.environment.createRawType((ReferenceBinding) binding, null/*no enclosing type*/);
-				else
-					// non-generic type binding
-					typeBinding = binding;
-	 			if (this.scanner.isAtFieldOrMethodStart()) {
-	 				switch (this.scanner.nextToken()) {
-		 				case BindingKeyScanner.FIELD:
-		 					return getFieldBinding(((ReferenceBinding) typeBinding).fields());
-		 				case BindingKeyScanner.METHOD:
-		 					MethodBinding methodBinding = getMethodBinding(((ReferenceBinding) typeBinding).methods());
-		 					if (this.scanner.isAtParametersStart())
-		 						// parameterized generic method binding
-		 						methodBinding = getParameterizedGenericMethodBinding(methodBinding);
-		 					if (this.scanner.isAtLocalVariableStart()) {
-		 						MethodScope methodScope = methodBinding.sourceMethod().scope;
-		 						return getLocalVariableBinding(methodScope);
-		 					} else
-		 						return methodBinding;
-	 				}
-	 				return null; // malformed key
-	 			} else if (this.scanner.isAtTypeVariableStart()) {
-	 				return getTypeVariableBinding((SourceTypeBinding) binding);
-	 			} else {
-	 				return getArrayBinding(dim, typeBinding);
-	 			}
-	 	}
-	 	return null;
-	 }
-	 
-	 /*
-	  * Returns the compiler binding corresponding to this key.
-	  * Returns null is malformed.
-	  * This key's scanner should be positioned on the package token.
-	  */
-	 Binding getCompilerBinding() {
-		CompilationUnitDeclaration parsedUnit = getCompilationUnitDeclaration();
-		if (parsedUnit != null) {
-			char[] fileName = parsedUnit.compilationResult.getFileName();
-			// don't resolve a second time the same unit (this would create the same bindingd twice)
-			if (!this.resolver.requestedKeys.containsKey(fileName) && !this.resolver.requestedSources.containsKey(fileName))
-				this.resolver.process(parsedUnit, this.resolver.totalUnits+1);
-		}
-		return getCompilerBinding(parsedUnit);
-	 }
-
-	/*
-	 * Finds the field binding that corresponds to this key in the given field bindings.
-	 * Returns null if not found.
-	 * This key's scanner should be positioned on the field name.
-	 */
-	FieldBinding getFieldBinding(FieldBinding[] fields) {
-	 	if (fields == null) return null;
-	 	char[] fieldName = this.scanner.getTokenSource();
-	 	for (int i = 0, length = fields.length; i < length; i++) {
-			FieldBinding field = fields[i];
-			if (CharOperation.equals(fieldName, field.name)) 
-				return field;
-		}
-	 	return null;
-	 }
-	 
-	 /*
-	  * Ensures that the given generic type binding corresponds to this key.
-	  * This key's scanner should be positionned on the first type parameter name token.
-	  */
-	 SourceTypeBinding getGenericTypeBinding(SourceTypeBinding typeBinding) {
-	 	TypeVariableBinding[] typeVariableBindings = typeBinding.typeVariables();
-	 	for (int i = 0, length = typeVariableBindings.length; i < length; i++) {
-			TypeVariableBinding typeVariableBinding = typeVariableBindings[i];
-			if (this.scanner.nextToken() != BindingKeyScanner.TYPE)
-				return null;
-		 	char[] typeVariableName = this.scanner.getTokenSource();
-			if (!CharOperation.equals(typeVariableName, typeVariableBinding.sourceName()))
-				return null;
-		}
-	 	return typeBinding;
-	 }
-	 
-	 /*
-	  * Returns the string that this binding key wraps.
-	  */
-	 String getKey() {
-	 	return new String(this.scanner.source);
-	 }
-	 
-	 LocalVariableBinding getLocalVariableBinding(BlockScope scope) {
-	 	if (this.scanner.nextToken() != BindingKeyScanner.LOCAL_VAR)
-			return null; // malformed key
-		char[] varName = this.scanner.getTokenSource();
-		if (Character.isDigit(varName[0])) {
-			int index = Integer.parseInt(new String(varName));
-			if (index >= scope.subscopeCount)
-				return null; // malformed key
-			if (!this.scanner.isAtLocalVariableStart())
-				return null; // malformed key
-			return getLocalVariableBinding((BlockScope) scope.subscopes[index]);
-		} else {
-		 	for (int i = 0; i < scope.localIndex; i++) {
-				LocalVariableBinding local = scope.locals[i];
-				if (CharOperation.equals(varName, local.name))
-					return local;
-			}
-		}
-	 	return null;
-	 }
-	 
-	/*
-	 * Finds the method binding that corresponds to this key in the given method bindings.
-	 * Returns null if not found.
-	 * This key's scanner should be positioned on the selector token.
-	 */
-	 MethodBinding getMethodBinding(MethodBinding[] methods) {
-	 	if (methods == null) return null;
-	 	char[] selector = this.scanner.getTokenSource();
-	 	this.scanner.skipMethodSignature();
-	 	char[] signature = this.scanner.getTokenSource();
-	 	
-	 	nextMethod: for (int i = 0, methodLength = methods.length; i < methodLength; i++) {
-			MethodBinding method = methods[i];
-			if (CharOperation.equals(selector, method.selector) || (selector.length == 0 && method.isConstructor())) {
-				if (CharOperation.equals(signature, method.genericSignature()))
-					return method;
-				return method;
-			}
-		}
-	 	return null;
-	 }
-	 
-	 
-	 /*
-	  * Finds parameterized generic method binding that corresponds to this key.
-	  * This key's scanner should be positionned on the first type argument name token.
-	  */
-	 ParameterizedGenericMethodBinding getParameterizedGenericMethodBinding(MethodBinding methodBinding) {
-	 	int length = methodBinding.typeVariables().length;
-	 	TypeBinding[] arguments = new TypeBinding[length];
-	 	for (int i = 0; i < length; i++) {
-			reset();
-			Binding argument = getCompilerBinding();
-			if (argument == null) 
-				return null;
-			arguments[i] = (TypeBinding) argument;
-		}
-	 	return new ParameterizedGenericMethodBinding(methodBinding, arguments, this.environment);
-	 }
-	 
-	 /*
-	  * Finds parameterized type binding that corresponds to this key.
-	  * This key's scanner should be positionned on the first type argument name token.
-	  */
-	 ParameterizedTypeBinding getParameterizedTypeBinding(ReferenceBinding genericType, ReferenceBinding enclosingType) {
-	 	TypeVariableBinding[] typeVariableBindings = genericType.typeVariables();
-	 	int length = typeVariableBindings.length;
-	 	TypeBinding[] arguments = new TypeBinding[length];
-	 	for (int i = 0; i < length; i++) {
-	 		TypeBinding argument;
-	 		if (this.scanner.isAtWildCardStart()) {
-	 			argument = getWildCardBinding(genericType, i);
-	 		} else {
-				reset();
-				argument = (TypeBinding) getCompilerBinding();
-	 		}
-			if (argument == null) 
-				return this.environment.createRawType(genericType, enclosingType);
-			arguments[i] =argument;
-	 		
-		}
-	 	ParameterizedTypeBinding parameterizedTypeBinding = this.environment.createParameterizedType(genericType, arguments, enclosingType);
-	 	// skip ";>"
-	 	this.scanner.skipParametersEnd();
-	 	if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == BindingKeyScanner.TYPE) {
-	 		char[] typeName = this.scanner.getTokenSource();
-	 		ReferenceBinding memberType = genericType.getMemberType(typeName);
-	 		return getParameterizedTypeBinding(memberType, parameterizedTypeBinding);
-	 	} else {
-		 	return parameterizedTypeBinding;
-	 	}
-	 }
-	 
-	/*
-	 * Finds the type binding that corresponds to this key in the given type bindings.
-	 * Returns null if not found.
-	 * This key's scanner should be positioned on the type name token.
-	 */
-	 TypeBinding getTypeBinding(CompilationUnitDeclaration parsedUnit, TypeDeclaration[] types, char[] typeName) {
-	 	if (Character.isDigit(typeName[0])) {
-	 		// anonymous or local type
-	 		int nextToken = BindingKeyScanner.TYPE;
-	 		while (this.scanner.isAtMemberTypeStart()) 
-	 			nextToken = this.scanner.nextToken();
-	 		typeName = nextToken == BindingKeyScanner.END ? this.scanner.source : CharOperation.subarray(this.scanner.source, 0, this.scanner.index+1);
-	 		LocalTypeBinding[] localTypeBindings  = parsedUnit.localTypes;
-	 		for (int i = 0; i < parsedUnit.localTypeCount; i++)
-	 			if (CharOperation.equals(typeName, localTypeBindings[i].signature()))
-	 				return localTypeBindings[i];
-	 		return null;
-	 	} else {
-	 		// member type
-		 	if (types == null) return null;
-			for (int i = 0, length = types.length; i < length; i++) {
-				TypeDeclaration declaration = types[i];
-				if (CharOperation.equals(typeName, declaration.name)) {
-					if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == BindingKeyScanner.TYPE)
-						return getTypeBinding(parsedUnit, declaration.memberTypes, this.scanner.getTokenSource());
-					else
-						return declaration.binding;
-				}
-			}
-	 	}
-		return null;
-	 }
-	 
-	 TypeVariableBinding getTypeVariableBinding(SourceTypeBinding typeBinding) {
-	 	// skip ";>"
-	 	this.scanner.skipParametersEnd();
-		if (this.scanner.nextToken() != BindingKeyScanner.TYPE)
-			return null;
-	 	char[] typeVariableName = this.scanner.getTokenSource();
-	 	TypeVariableBinding[] typeVariableBindings = typeBinding.typeVariables();
-	 	for (int i = 0, length = typeVariableBindings.length; i < length; i++) {
-			TypeVariableBinding typeVariableBinding = typeVariableBindings[i];
-			if (CharOperation.equals(typeVariableName, typeVariableBinding.sourceName()))
-				return typeVariableBinding;
-		}
-	 	return null;
-	 }
-	 
-	 TypeBinding getWildCardBinding(ReferenceBinding genericType, int rank) {
-	 	if (this.scanner.nextToken() != BindingKeyScanner.TYPE) return null;
-	 	char[] source = this.scanner.getTokenSource();
-	 	if (source.length == 0) return null; //malformed key
-	 	int kind = -1;
-	 	TypeBinding bound = null;
-	 	switch (source[0]) {
-		 	case '*':
-		 		kind = Wildcard.UNBOUND;
-		 		break;
-		 	case '+':
-		 		reset();
-		 		kind = Wildcard.EXTENDS;
-		 		bound = (TypeBinding) getCompilerBinding();
-		 		break;
-		 	case '-':
-		 		reset();
-		 		kind = Wildcard.SUPER;
-		 		bound = (TypeBinding) getCompilerBinding();
-		 		break;
-	 	}
-	 	if (kind == -1) return null; // malformed key
-	 	if (kind != Wildcard.UNBOUND && bound == null) return null; // malformed key
- 		return this.environment.createWildcard(genericType, rank, bound, kind);
-	 }
-	 
-	 /*
-	  * Forget about this key's compound name and dimension.
-	  */
-	 void reset() {
-	 	this.compoundName = null;
-	 	this.dimension = 0;
-	 }
-	 
-	 public String toString() {
-		return getKey();
-	}
-
-}
diff --git a/dom/org/eclipse/jdt/core/dom/BindingKeyScanner.java b/dom/org/eclipse/jdt/core/dom/BindingKeyScanner.java
deleted file mode 100644
index 42c51e7..0000000
--- a/dom/org/eclipse/jdt/core/dom/BindingKeyScanner.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2004 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 org.eclipse.jdt.core.dom;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-/**
- * Internal class.
- * @since 3.1
- */
-class BindingKeyScanner {
-	
-	static final int START = -1;
-	static final int PACKAGE = 0;
-	static final int TYPE = 1;
-	static final int FIELD = 2;
-	static final int METHOD = 3;
-	static final int ARRAY = 4;
-	static final int LOCAL_VAR = 5;
-	static final int END = 6;
-	
-	int index = 0, start;
-	char[] source;
-	int token = START;
-
-	BindingKeyScanner(char[] source) {
-		this.source = source;
-	}
-	
-	char[] getTokenSource() {
-		int length = this.index-this.start;
-		char[] result = new char[length];
-		System.arraycopy(this.source, this.start, result, 0, length);
-		return result;
-	}
-	
-	boolean isAtFieldOrMethodStart() {
-		return 
-			this.index+1 < this.source.length
-			&& this.source[this.index+1] == '.';
-	}
-	
-	boolean isAtLocalVariableStart() {
-		return 
-			this.index < this.source.length
-			&& this.source[this.index] == '#';
-	}
-	
-	boolean isAtMemberTypeStart() {
-		return 
-			this.index < this.source.length
-			&& (this.source[this.index] == '$'
-				|| (this.source[this.index] == '.' && this.source[this.index-1] == '>'));
-	}
-	
-	boolean isAtParametersStart() {
-		char currentChar;
-		return 
-			this.index > 0
-			&& this.index < this.source.length
-			&& ((currentChar = this.source[this.index]) == '<'
-				|| currentChar == '%');
-	}
-	
-	boolean isAtTypeParameterStart() {
-		return 
-			this.index+1 < this.source.length
-			&& this.source[this.index+1] == 'T';
-	}
-	
-	boolean isAtTypeVariableStart() {
-		return 
-			this.index+3 < this.source.length
-			&& this.source[this.index+3] == ':';
-	}
-
-	boolean isAtTypeStart() {
-		return this.index+1 < this.source.length && "LIZVCDBFJS[".indexOf(this.source[this.index+1]) != -1; //$NON-NLS-1$
-	}
-	
-	boolean isAtWildCardStart() {
-		return this.index+1 < this.source.length && "*+-".indexOf(this.source[this.index+1]) != -1; //$NON-NLS-1$
-	}
-	
-	int nextToken() {
-		int previousTokenEnd = this.index;
-		this.start = this.index;
-		int length = this.source.length;
-		while (this.index <= length) {
-			char currentChar = this.index == length ? Character.MIN_VALUE : this.source[this.index];
-			switch (currentChar) {
-				case 'B':
-				case 'C':
-				case 'D':
-				case 'F':
-				case 'I':
-				case 'J':
-				case 'S':
-				case 'V':
-				case 'Z':
-					// base type
-					if (this.index == previousTokenEnd) {
-						this.index++;
-						this.token = TYPE;
-						return this.token;
-					}
-					break;
-				case 'L':
-				case 'T':
-					if (this.index == previousTokenEnd) {
-						this.start = this.index+1;
-					}
-					break;
-				case ';':
-				case '$':
-					if (this.index == previousTokenEnd) {
-						this.start = this.index+1;
-						previousTokenEnd = this.start;
-					} else {
-						this.token = TYPE;
-						return this.token;
-					}
-					break;
-				case '.':
-				case '%':
-				case ':':
-					this.start = this.index+1;
-					previousTokenEnd = this.start;
-					break;
-				case '[':
-					while (this.index < length && this.source[this.index] == '[')
-						this.index++;
-					this.token = ARRAY;
-					return this.token;
-				case '<':
-					if (this.index == previousTokenEnd) {
-						this.start = this.index+1;
-						previousTokenEnd = this.start;
-					} else if (this.start > 0) {
-						switch (this.source[this.start-1]) {
-							case '.':
-								if (this.source[this.start-2] == '>')
-									// case of member type where enclosing type is parameterized
-									this.token = TYPE;
-								else
-									this.token = METHOD;
-								return this.token;
-							default:
-								this.token = TYPE;
-								return this.token;
-						}
-					} 
-					break;
-				case '(':
-					this.token = METHOD;
-					return this.token;
-				case ')':
-					this.start = ++this.index;
-					this.token = END;
-					return this.token;
-				case '#':
-					if (this.index == previousTokenEnd) {
-						this.start = this.index+1;
-						previousTokenEnd = this.start;
-					} else {
-						this.token = LOCAL_VAR;
-						return this.token;
-					}
-					break;
-				case Character.MIN_VALUE:
-					switch (this.token) {
-						case START:
-							this.token = PACKAGE;
-							break;
-						case METHOD:
-						case LOCAL_VAR:
-							this.token = LOCAL_VAR;
-							break;
-						case TYPE:
-							if (this.index > this.start && this.source[this.start-1] == '.')
-								this.token = FIELD;
-							else
-								this.token = END;
-							break;
-						default:
-							this.token = END;
-							break;
-					}
-					return this.token;
-				case '*':
-				case '+':
-				case '-':
-					this.index++;
-					this.token = TYPE;
-					return this.token;
-			}
-			this.index++;
-		}
-		this.token = END;
-		return this.token;
-	}
-	
-	void skipMethodSignature() {
-		char currentChar;
-		while (this.index < this.source.length && (currentChar = this.source[this.index]) != '#' && currentChar != '%')
-			this.index++;
-	}
-	
-	void skipParametersEnd() {
-		while (this.index < this.source.length && this.source[this.index] != '>')
-			this.index++;
-		this.index++;
-	}
-	
-	public String toString() {
-		StringBuffer buffer = new StringBuffer();
-		switch (this.token) {
-			case START:
-				buffer.append("START: "); //$NON-NLS-1$
-				break;
-			case PACKAGE:
-				buffer.append("PACKAGE: "); //$NON-NLS-1$
-				break;
-			case TYPE:
-				buffer.append("TYPE: "); //$NON-NLS-1$
-				break;
-			case FIELD:
-				buffer.append("FIELD: "); //$NON-NLS-1$
-				break;
-			case METHOD:
-				buffer.append("METHOD: "); //$NON-NLS-1$
-				break;
-			case ARRAY:
-				buffer.append("ARRAY: "); //$NON-NLS-1$
-				break;
-			case LOCAL_VAR:
-				buffer.append("LOCAL VAR: "); //$NON-NLS-1$
-				break;
-			case END:
-				buffer.append("END: "); //$NON-NLS-1$
-				break;
-		}
-		if (this.index < 0) {
-			buffer.append("**"); //$NON-NLS-1$
-			buffer.append(this.source);
-		} else if (this.index <= this.source.length) {
-			buffer.append(CharOperation.subarray(this.source, 0, this.start));
-			buffer.append('*');
-			if (this.start <= this.index) {
-				buffer.append(CharOperation.subarray(this.source, this.start, this.index));
-				buffer.append('*');
-				buffer.append(CharOperation.subarray(this.source, this.index, this.source.length));
-			} else {
-				buffer.append('*');
-				buffer.append(CharOperation.subarray(this.source, this.start, this.source.length));
-			}
-		} else {
-			buffer.append(this.source);
-			buffer.append("**"); //$NON-NLS-1$
-		}
-		return buffer.toString();
-	}
-
-}
diff --git a/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
index d514860..fee3814 100644
--- a/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
+++ b/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
@@ -53,6 +53,7 @@
 import org.eclipse.jdt.internal.core.NameLookup;
 import org.eclipse.jdt.internal.core.SourceRefElement;
 import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
+import org.eclipse.jdt.internal.core.util.BindingKey;
 import org.eclipse.jdt.internal.core.util.CommentRecorderParser;
 import org.eclipse.jdt.internal.core.util.DOMFinder;
 
@@ -186,7 +187,7 @@
 		// walk the binding keys
 		this.requestedKeys = new HashtableOfObject();
 		for (int i = 0; i < keyLength; i++) {
-			BindingKey bindingKey = new BindingKey(bindingKeys[i], this);
+			BindingKey bindingKey = new BindingKey(bindingKeys[i], this, this.lookupEnvironment);
 			CompilationUnitDeclaration parsedUnit = bindingKey.getCompilationUnitDeclaration();
 			if (parsedUnit != null) {
 				char[] fileName = parsedUnit.compilationResult.getFileName();
@@ -204,12 +205,12 @@
 					
 			} else {
 				switch (bindingKey.scanner.token) {
-					case BindingKeyScanner.PACKAGE:
+					case BindingKey.Scanner.PACKAGE:
 						// package binding key
 						char[] pkgName = CharOperation.concatWith(bindingKey.compoundName(), '.');
 						this.requestedKeys.put(pkgName, bindingKey);
 						break;
-					case BindingKeyScanner.TYPE:
+					case BindingKey.Scanner.TYPE:
 						// base type binding
 						char[] key = bindingKey.scanner.source;
 						this.requestedKeys.put(key, bindingKey);
@@ -225,7 +226,7 @@
 	IBinding createBinding(String key) {
 		if (this.bindingTables == null)
 			throw new RuntimeException("Cannot be called outside ASTParser#createASTs(...)"); //$NON-NLS-1$
-		BindingKey bindingKey = new BindingKey(key, this);
+		BindingKey bindingKey = new BindingKey(key, this, this.lookupEnvironment);
 		Binding compilerBinding = bindingKey.getCompilerBinding();
 		if (compilerBinding == null) return null;
 		DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null/*no owner*/, this.bindingTables);
@@ -289,6 +290,12 @@
 	public void initializeParser() {
 		this.parser = new CommentRecorderParser(this.problemReporter, false);
 	}
+	public void process(CompilationUnitDeclaration unit, int i) {
+		// don't resolve a second time the same unit (this would create the same binding twice)
+		char[] fileName = unit.compilationResult.getFileName();
+		if (!this.requestedKeys.containsKey(fileName) && !this.requestedSources.containsKey(fileName))
+			super.process(unit, i);
+	}
 	/*
 	 * Compiler crash recovery in case of unexpected runtime exceptions
 	 */
@@ -618,7 +625,7 @@
 			for (; i < this.totalUnits; i++) {
 				unit = this.unitsToProcess[i];
 				try {
-					process(unit, i);
+					super.process(unit, i); // this.process(...) is optimized to not process already known units
 					
 					ICompilationUnit source = (ICompilationUnit) this.requestedSources.removeKey(unit.compilationResult.getFileName());
 					if (source != null) {
diff --git a/model/org/eclipse/jdt/internal/core/util/BindingKey.java b/model/org/eclipse/jdt/internal/core/util/BindingKey.java
new file mode 100644
index 0000000..52d6877
--- /dev/null
+++ b/model/org/eclipse/jdt/internal/core/util/BindingKey.java
@@ -0,0 +1,699 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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 org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypes;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/*
+ * A wrapper class arround a binding key (see Binding#computeUniqueKey()).
+ * This decodes a binding keys, and optionally creates the corresponding compiler binding,
+ * or computes its signature.
+ */
+public class BindingKey {
+	
+	public class Scanner {
+		
+		public static final int START = -1;
+		public static final int PACKAGE = 0;
+		public static final int TYPE = 1;
+		public static final int FIELD = 2;
+		public static final int METHOD = 3;
+		public static final int ARRAY = 4;
+		public static final int LOCAL_VAR = 5;
+		public static final int END = 6;
+		
+		int index = 0, start;
+		public char[] source;
+		public int token = START;
+	
+		Scanner(char[] source) {
+			this.source = source;
+		}
+		
+		char[] getTokenSource() {
+			int length = this.index-this.start;
+			char[] result = new char[length];
+			System.arraycopy(this.source, this.start, result, 0, length);
+			return result;
+		}
+		
+		boolean isAtFieldOrMethodStart() {
+			return 
+				this.index+1 < this.source.length
+				&& this.source[this.index+1] == '.';
+		}
+		
+		boolean isAtLocalVariableStart() {
+			return 
+				this.index < this.source.length
+				&& this.source[this.index] == '#';
+		}
+		
+		boolean isAtMemberTypeStart() {
+			return 
+				this.index < this.source.length
+				&& (this.source[this.index] == '$'
+					|| (this.source[this.index] == '.' && this.source[this.index-1] == '>'));
+		}
+		
+		boolean isAtParametersStart() {
+			char currentChar;
+			return 
+				this.index > 0
+				&& this.index < this.source.length
+				&& ((currentChar = this.source[this.index]) == '<'
+					|| currentChar == '%');
+		}
+		
+		boolean isAtTypeParameterStart() {
+			return 
+				this.index+1 < this.source.length
+				&& this.source[this.index+1] == 'T';
+		}
+		
+		boolean isAtTypeVariableStart() {
+			return 
+				this.index+3 < this.source.length
+				&& this.source[this.index+3] == ':';
+		}
+	
+		boolean isAtTypeStart() {
+			return this.index+1 < this.source.length && "LIZVCDBFJS[".indexOf(this.source[this.index+1]) != -1; //$NON-NLS-1$
+		}
+		
+		boolean isAtWildCardStart() {
+			return this.index+1 < this.source.length && "*+-".indexOf(this.source[this.index+1]) != -1; //$NON-NLS-1$
+		}
+		
+		int nextToken() {
+			int previousTokenEnd = this.index;
+			this.start = this.index;
+			int length = this.source.length;
+			while (this.index <= length) {
+				char currentChar = this.index == length ? Character.MIN_VALUE : this.source[this.index];
+				switch (currentChar) {
+					case 'B':
+					case 'C':
+					case 'D':
+					case 'F':
+					case 'I':
+					case 'J':
+					case 'S':
+					case 'V':
+					case 'Z':
+						// base type
+						if (this.index == previousTokenEnd) {
+							this.index++;
+							this.token = TYPE;
+							return this.token;
+						}
+						break;
+					case 'L':
+					case 'T':
+						if (this.index == previousTokenEnd) {
+							this.start = this.index+1;
+						}
+						break;
+					case ';':
+					case '$':
+						if (this.index == previousTokenEnd) {
+							this.start = this.index+1;
+							previousTokenEnd = this.start;
+						} else {
+							this.token = TYPE;
+							return this.token;
+						}
+						break;
+					case '.':
+					case '%':
+					case ':':
+						this.start = this.index+1;
+						previousTokenEnd = this.start;
+						break;
+					case '[':
+						while (this.index < length && this.source[this.index] == '[')
+							this.index++;
+						this.token = ARRAY;
+						return this.token;
+					case '<':
+						if (this.index == previousTokenEnd) {
+							this.start = this.index+1;
+							previousTokenEnd = this.start;
+						} else if (this.start > 0) {
+							switch (this.source[this.start-1]) {
+								case '.':
+									if (this.source[this.start-2] == '>')
+										// case of member type where enclosing type is parameterized
+										this.token = TYPE;
+									else
+										this.token = METHOD;
+									return this.token;
+								default:
+									this.token = TYPE;
+									return this.token;
+							}
+						} 
+						break;
+					case '(':
+						this.token = METHOD;
+						return this.token;
+					case ')':
+						this.start = ++this.index;
+						this.token = END;
+						return this.token;
+					case '#':
+						if (this.index == previousTokenEnd) {
+							this.start = this.index+1;
+							previousTokenEnd = this.start;
+						} else {
+							this.token = LOCAL_VAR;
+							return this.token;
+						}
+						break;
+					case Character.MIN_VALUE:
+						switch (this.token) {
+							case START:
+								this.token = PACKAGE;
+								break;
+							case METHOD:
+							case LOCAL_VAR:
+								this.token = LOCAL_VAR;
+								break;
+							case TYPE:
+								if (this.index > this.start && this.source[this.start-1] == '.')
+									this.token = FIELD;
+								else
+									this.token = END;
+								break;
+							default:
+								this.token = END;
+								break;
+						}
+						return this.token;
+					case '*':
+					case '+':
+					case '-':
+						this.index++;
+						this.token = TYPE;
+						return this.token;
+				}
+				this.index++;
+			}
+			this.token = END;
+			return this.token;
+		}
+		
+		void skipMethodSignature() {
+			char currentChar;
+			while (this.index < this.source.length && (currentChar = this.source[this.index]) != '#' && currentChar != '%')
+				this.index++;
+		}
+		
+		void skipParametersEnd() {
+			while (this.index < this.source.length && this.source[this.index] != '>')
+				this.index++;
+			this.index++;
+		}
+		
+		public String toString() {
+			StringBuffer buffer = new StringBuffer();
+			switch (this.token) {
+				case START:
+					buffer.append("START: "); //$NON-NLS-1$
+					break;
+				case PACKAGE:
+					buffer.append("PACKAGE: "); //$NON-NLS-1$
+					break;
+				case TYPE:
+					buffer.append("TYPE: "); //$NON-NLS-1$
+					break;
+				case FIELD:
+					buffer.append("FIELD: "); //$NON-NLS-1$
+					break;
+				case METHOD:
+					buffer.append("METHOD: "); //$NON-NLS-1$
+					break;
+				case ARRAY:
+					buffer.append("ARRAY: "); //$NON-NLS-1$
+					break;
+				case LOCAL_VAR:
+					buffer.append("LOCAL VAR: "); //$NON-NLS-1$
+					break;
+				case END:
+					buffer.append("END: "); //$NON-NLS-1$
+					break;
+			}
+			if (this.index < 0) {
+				buffer.append("**"); //$NON-NLS-1$
+				buffer.append(this.source);
+			} else if (this.index <= this.source.length) {
+				buffer.append(CharOperation.subarray(this.source, 0, this.start));
+				buffer.append('*');
+				if (this.start <= this.index) {
+					buffer.append(CharOperation.subarray(this.source, this.start, this.index));
+					buffer.append('*');
+					buffer.append(CharOperation.subarray(this.source, this.index, this.source.length));
+				} else {
+					buffer.append('*');
+					buffer.append(CharOperation.subarray(this.source, this.start, this.source.length));
+				}
+			} else {
+				buffer.append(this.source);
+				buffer.append("**"); //$NON-NLS-1$
+			}
+			return buffer.toString();
+		}
+	
+	}
+	
+	char[][] compoundName;
+	int dimension;
+	public Scanner scanner;
+	Compiler compiler;
+	LookupEnvironment environment;
+	
+	public BindingKey(String key) {
+		this(key, null, null);
+	}
+
+	public BindingKey(String key, Compiler compiler, LookupEnvironment environment) {
+		this.scanner = new Scanner(key.toCharArray());
+		this.compiler = compiler;
+		this.environment = environment;
+		reset();
+	}
+	
+	/*
+	 * If not already cached, computes and cache the compound name (pkg name + top level name) of this key.
+	 * Returns the package name if key is a pkg key.
+	 * Returns an empty array if malformed.
+	 * This key's scanner should be positioned on the package or type token.
+	 */
+	public char[][] compoundName() {
+		if (this.compoundName == null) {
+			switch(this.scanner.nextToken()) {
+				case Scanner.PACKAGE:
+				case Scanner.TYPE:
+	 				this.compoundName = CharOperation.splitOn('/', this.scanner.getTokenSource());
+	 				break;
+		 		case Scanner.ARRAY:
+		 			this.dimension = this.scanner.getTokenSource().length;
+	 				if (this.scanner.nextToken() == Scanner.TYPE)
+		 				this.compoundName = CharOperation.splitOn('/', this.scanner.getTokenSource());
+	 				else
+	 					// malformed key
+				 		this.compoundName = CharOperation.NO_CHAR_CHAR;
+		 			break;
+				default:
+		 			// malformed key
+		 			this.compoundName = CharOperation.NO_CHAR_CHAR;
+					break;
+			}
+		}
+		return this.compoundName;
+	}
+	
+	/*
+	 * If the given dimension is greater than 0 returns an array binding for the given type binding.
+	 * Otherwise return the given type binding.
+	 * Returns null if the given type binding is null.
+	 */
+	TypeBinding getArrayBinding(int dim, TypeBinding binding) {
+		if (binding == null) return null;
+		if (dim == 0) return binding;
+		return this.environment.createArrayType(binding, dim);
+	}
+	
+	TypeBinding getBaseTypeBinding(char[] signature) {
+		switch (signature[0]) {
+			case 'I' :
+				return BaseTypes.IntBinding;
+			case 'Z' :
+				return BaseTypes.BooleanBinding;
+			case 'V' :
+				return BaseTypes.VoidBinding;
+			case 'C' :
+				return BaseTypes.CharBinding;
+			case 'D' :
+				return BaseTypes.DoubleBinding;
+			case 'B' :
+				return BaseTypes.ByteBinding;
+			case 'F' :
+				return BaseTypes.FloatBinding;
+			case 'J' :
+				return BaseTypes.LongBinding;
+			case 'S' :
+				return BaseTypes.ShortBinding;
+			default :
+				return null;
+		}
+	}
+	 
+	/*
+	 * Returns a binary binding corresonding to this key's compound name.
+	 * Returns null if not found.
+	 * This key's scanner should be positioned on the token after the top level type.
+	 */
+	TypeBinding getBinaryBinding() {
+		TypeBinding binding = this.environment.getType(this.compoundName);
+		return getArrayBinding(this.dimension, binding);
+	}
+	 
+	/*
+	 * Finds the compilation unit declaration corresponding to the key in the given lookup environment.
+	 * Returns null if no compilation unit declaration could be found.
+	 * This key's scanner should be positioned on the package token.
+	 */
+	public CompilationUnitDeclaration getCompilationUnitDeclaration() {
+		char[][] name = compoundName();
+		if (name.length == 0) return null;
+		if (this.environment == null) return null;
+		ReferenceBinding binding = this.environment.getType(name);
+		if (!(binding instanceof SourceTypeBinding)) return null;
+		return ((SourceTypeBinding) binding).scope.compilationUnitScope().referenceContext;
+	}
+	 
+	public Binding getCompilerBinding(CompilationUnitDeclaration parsedUnit) {
+		if (this.environment == null) return null;
+		switch (this.scanner.token) {
+			case Scanner.PACKAGE:
+	 			return new PackageBinding(this.compoundName, null, this.environment);
+	 		case Scanner.TYPE:
+	 			if (this.compoundName.length == 1 && this.compoundName[0].length == 1) {
+	 				// case of base type
+		 			TypeBinding baseTypeBinding = getBaseTypeBinding(this.compoundName[0]);
+		 			if (baseTypeBinding != null) 
+	 					return getArrayBinding(this.dimension, baseTypeBinding);
+	 			}
+	 			char[] typeName = this.compoundName[this.compoundName.length-1];
+	 			int dim = this.dimension;
+	 			TypeBinding binding = parsedUnit == null ? getBinaryBinding() : getTypeBinding(parsedUnit, parsedUnit.types, typeName);
+	 			if (binding == null) return null;
+				TypeBinding typeBinding = null;
+				if (this.scanner.isAtParametersStart()) {
+					if (this.scanner.isAtTypeParameterStart())	 					
+	 					// generic type binding
+	 					typeBinding = getGenericTypeBinding((SourceTypeBinding) binding);
+	 				else if (this.scanner.isAtTypeStart() || this.scanner.isAtWildCardStart())
+						// parameterized type binding
+	 					typeBinding = getParameterizedTypeBinding((ReferenceBinding) binding, null/*no enclosing type*/); 
+				} else if (binding.typeVariables().length > 0)
+					// raw type binding
+					typeBinding = this.environment.createRawType((ReferenceBinding) binding, null/*no enclosing type*/);
+				else
+					// non-generic type binding
+					typeBinding = binding;
+	 			if (this.scanner.isAtFieldOrMethodStart()) {
+	 				switch (this.scanner.nextToken()) {
+		 				case Scanner.FIELD:
+		 					return getFieldBinding(((ReferenceBinding) typeBinding).fields());
+		 				case Scanner.METHOD:
+		 					MethodBinding methodBinding = getMethodBinding(((ReferenceBinding) typeBinding).methods());
+		 					if (this.scanner.isAtParametersStart())
+		 						// parameterized generic method binding
+		 						methodBinding = getParameterizedGenericMethodBinding(methodBinding);
+		 					if (this.scanner.isAtLocalVariableStart()) {
+		 						MethodScope methodScope = methodBinding.sourceMethod().scope;
+		 						return getLocalVariableBinding(methodScope);
+		 					} else
+		 						return methodBinding;
+	 				}
+	 				return null; // malformed key
+	 			} else if (this.scanner.isAtTypeVariableStart()) {
+	 				return getTypeVariableBinding((SourceTypeBinding) binding);
+	 			} else {
+	 				return getArrayBinding(dim, typeBinding);
+	 			}
+	 	}
+	 	return null;
+	 }
+	 
+	/*
+	 * Returns the compiler binding corresponding to this key.
+	 * Returns null is malformed.
+	 * This key's scanner should be positioned on the package token.
+	 */
+	public Binding getCompilerBinding() {
+		CompilationUnitDeclaration parsedUnit = getCompilationUnitDeclaration();
+		if (parsedUnit != null && this.compiler != null) {
+			this.compiler.process(parsedUnit, this.compiler.totalUnits+1); // noop if unit has already been resolved
+		}
+		return getCompilerBinding(parsedUnit);
+	}
+
+	/*
+	 * Finds the field binding that corresponds to this key in the given field bindings.
+	 * Returns null if not found.
+	 * This key's scanner should be positioned on the field name.
+	 */
+	FieldBinding getFieldBinding(FieldBinding[] fields) {
+	 	if (fields == null) return null;
+	 	char[] fieldName = this.scanner.getTokenSource();
+	 	for (int i = 0, length = fields.length; i < length; i++) {
+			FieldBinding field = fields[i];
+			if (CharOperation.equals(fieldName, field.name)) 
+				return field;
+		}
+	 	return null;
+	 }
+	 
+	 /*
+	  * Ensures that the given generic type binding corresponds to this key.
+	  * This key's scanner should be positionned on the first type parameter name token.
+	  */
+	 SourceTypeBinding getGenericTypeBinding(SourceTypeBinding typeBinding) {
+	 	TypeVariableBinding[] typeVariableBindings = typeBinding.typeVariables();
+	 	for (int i = 0, length = typeVariableBindings.length; i < length; i++) {
+			TypeVariableBinding typeVariableBinding = typeVariableBindings[i];
+			if (this.scanner.nextToken() != Scanner.TYPE)
+				return null;
+		 	char[] typeVariableName = this.scanner.getTokenSource();
+			if (!CharOperation.equals(typeVariableName, typeVariableBinding.sourceName()))
+				return null;
+		}
+	 	return typeBinding;
+	 }
+	 
+	/*
+	 * Returns the string that this binding key wraps.
+	 */
+	public String getKey() {
+		return new String(this.scanner.source);
+	}
+	 
+	 LocalVariableBinding getLocalVariableBinding(BlockScope scope) {
+	 	if (this.scanner.nextToken() != Scanner.LOCAL_VAR)
+			return null; // malformed key
+		char[] varName = this.scanner.getTokenSource();
+		if (Character.isDigit(varName[0])) {
+			int index = Integer.parseInt(new String(varName));
+			if (index >= scope.subscopeCount)
+				return null; // malformed key
+			if (!this.scanner.isAtLocalVariableStart())
+				return null; // malformed key
+			return getLocalVariableBinding((BlockScope) scope.subscopes[index]);
+		} else {
+		 	for (int i = 0; i < scope.localIndex; i++) {
+				LocalVariableBinding local = scope.locals[i];
+				if (CharOperation.equals(varName, local.name))
+					return local;
+			}
+		}
+	 	return null;
+	 }
+	 
+	/*
+	 * Finds the method binding that corresponds to this key in the given method bindings.
+	 * Returns null if not found.
+	 * This key's scanner should be positioned on the selector token.
+	 */
+	 MethodBinding getMethodBinding(MethodBinding[] methods) {
+	 	if (methods == null) return null;
+	 	char[] selector = this.scanner.getTokenSource();
+	 	this.scanner.skipMethodSignature();
+	 	char[] signature = this.scanner.getTokenSource();
+	 	
+	 	nextMethod: for (int i = 0, methodLength = methods.length; i < methodLength; i++) {
+			MethodBinding method = methods[i];
+			if (CharOperation.equals(selector, method.selector) || (selector.length == 0 && method.isConstructor())) {
+				if (CharOperation.equals(signature, method.genericSignature()))
+					return method;
+				return method;
+			}
+		}
+	 	return null;
+	 }
+	 
+	 
+	 /*
+	  * Finds parameterized generic method binding that corresponds to this key.
+	  * This key's scanner should be positionned on the first type argument name token.
+	  */
+	 ParameterizedGenericMethodBinding getParameterizedGenericMethodBinding(MethodBinding methodBinding) {
+	 	int length = methodBinding.typeVariables().length;
+	 	TypeBinding[] arguments = new TypeBinding[length];
+	 	for (int i = 0; i < length; i++) {
+			reset();
+			Binding argument = getCompilerBinding();
+			if (argument == null) 
+				return null;
+			arguments[i] = (TypeBinding) argument;
+		}
+	 	return new ParameterizedGenericMethodBinding(methodBinding, arguments, this.environment);
+	 }
+	 
+	 /*
+	  * Finds parameterized type binding that corresponds to this key.
+	  * This key's scanner should be positionned on the first type argument name token.
+	  */
+	 ParameterizedTypeBinding getParameterizedTypeBinding(ReferenceBinding genericType, ReferenceBinding enclosingType) {
+	 	TypeVariableBinding[] typeVariableBindings = genericType.typeVariables();
+	 	int length = typeVariableBindings.length;
+	 	TypeBinding[] arguments = new TypeBinding[length];
+	 	for (int i = 0; i < length; i++) {
+	 		TypeBinding argument;
+	 		if (this.scanner.isAtWildCardStart()) {
+	 			argument = getWildCardBinding(genericType, i);
+	 		} else {
+				reset();
+				argument = (TypeBinding) getCompilerBinding();
+	 		}
+			if (argument == null) 
+				return this.environment.createRawType(genericType, enclosingType);
+			arguments[i] =argument;
+	 		
+		}
+	 	ParameterizedTypeBinding parameterizedTypeBinding = this.environment.createParameterizedType(genericType, arguments, enclosingType);
+	 	// skip ";>"
+	 	this.scanner.skipParametersEnd();
+	 	if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == Scanner.TYPE) {
+	 		char[] typeName = this.scanner.getTokenSource();
+	 		ReferenceBinding memberType = genericType.getMemberType(typeName);
+	 		return getParameterizedTypeBinding(memberType, parameterizedTypeBinding);
+	 	} else {
+		 	return parameterizedTypeBinding;
+		}
+	}
+	
+	/*
+	 * Returns the signature of this binding key
+	 */
+	public String getSignature() {
+		return null; // TODO (jerome) implement
+	}
+	
+	/*
+	 * Finds the type binding that corresponds to this key in the given type bindings.
+	 * Returns null if not found.
+	 * This key's scanner should be positioned on the type name token.
+	 */
+	 TypeBinding getTypeBinding(CompilationUnitDeclaration parsedUnit, TypeDeclaration[] types, char[] typeName) {
+	 	if (Character.isDigit(typeName[0])) {
+	 		// anonymous or local type
+	 		int nextToken = Scanner.TYPE;
+	 		while (this.scanner.isAtMemberTypeStart()) 
+	 			nextToken = this.scanner.nextToken();
+	 		typeName = nextToken == Scanner.END ? this.scanner.source : CharOperation.subarray(this.scanner.source, 0, this.scanner.index+1);
+	 		LocalTypeBinding[] localTypeBindings  = parsedUnit.localTypes;
+	 		for (int i = 0; i < parsedUnit.localTypeCount; i++)
+	 			if (CharOperation.equals(typeName, localTypeBindings[i].signature()))
+	 				return localTypeBindings[i];
+	 		return null;
+	 	} else {
+	 		// member type
+		 	if (types == null) return null;
+			for (int i = 0, length = types.length; i < length; i++) {
+				TypeDeclaration declaration = types[i];
+				if (CharOperation.equals(typeName, declaration.name)) {
+					if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == Scanner.TYPE)
+						return getTypeBinding(parsedUnit, declaration.memberTypes, this.scanner.getTokenSource());
+					else
+						return declaration.binding;
+				}
+			}
+	 	}
+		return null;
+	 }
+	 
+	 TypeVariableBinding getTypeVariableBinding(SourceTypeBinding typeBinding) {
+	 	// skip ";>"
+	 	this.scanner.skipParametersEnd();
+		if (this.scanner.nextToken() != Scanner.TYPE)
+			return null;
+	 	char[] typeVariableName = this.scanner.getTokenSource();
+	 	TypeVariableBinding[] typeVariableBindings = typeBinding.typeVariables();
+	 	for (int i = 0, length = typeVariableBindings.length; i < length; i++) {
+			TypeVariableBinding typeVariableBinding = typeVariableBindings[i];
+			if (CharOperation.equals(typeVariableName, typeVariableBinding.sourceName()))
+				return typeVariableBinding;
+		}
+	 	return null;
+	 }
+	 
+	 TypeBinding getWildCardBinding(ReferenceBinding genericType, int rank) {
+	 	if (this.scanner.nextToken() != Scanner.TYPE) return null;
+	 	char[] source = this.scanner.getTokenSource();
+	 	if (source.length == 0) return null; //malformed key
+	 	int kind = -1;
+	 	TypeBinding bound = null;
+	 	switch (source[0]) {
+		 	case '*':
+		 		kind = Wildcard.UNBOUND;
+		 		break;
+		 	case '+':
+		 		reset();
+		 		kind = Wildcard.EXTENDS;
+		 		bound = (TypeBinding) getCompilerBinding();
+		 		break;
+		 	case '-':
+		 		reset();
+		 		kind = Wildcard.SUPER;
+		 		bound = (TypeBinding) getCompilerBinding();
+		 		break;
+	 	}
+	 	if (kind == -1) return null; // malformed key
+	 	if (kind != Wildcard.UNBOUND && bound == null) return null; // malformed key
+ 		return this.environment.createWildcard(genericType, rank, bound, kind);
+	 }
+	 
+	 /*
+	  * Forget about this key's compound name and dimension.
+	  */
+	 void reset() {
+	 	this.compoundName = null;
+	 	this.dimension = 0;
+	 }
+	 
+	 public String toString() {
+		return getKey();
+	}
+
+}