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();
+ }
+
+}