org.eclipse.jdt.core.dom.DefaultBindingResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.core.dom.DefaultBindingResolver.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2019 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Stephan Herrmann - Contribution for
 *                        Bug 342671 - ClassCastException: org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding cannot be cast to org.eclipse.jdt.internal.compiler.lookup.ArrayBinding
 *                        Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda
 *******************************************************************************/
package org.eclipse.jdt.core.dom;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.dom.MethodBinding.LambdaMethod;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.JavadocAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.JavadocFieldReference;
import org.eclipse.jdt.internal.compiler.ast.JavadocImplicitTypeReference;
import org.eclipse.jdt.internal.compiler.ast.JavadocMessageSend;
import org.eclipse.jdt.internal.compiler.ast.JavadocQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.JavadocSingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.JavadocSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Literal;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.ModuleReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Receiver;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemPackageBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.VoidTypeBinding;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.core.util.Util;

/**
 * Internal class for resolving bindings using old ASTs.
 * <p>
 * IMPORTANT: The methods on this class are synchronized. This is required
 * because there may be multiple clients in separate threads concurrently
 * reading an AST and asking for bindings for its nodes. These requests all
 * end up invoking instance methods on this class. There are various internal
 * tables and caches which are built and maintained in the course of looking
 * up bindings. To ensure that they remain coherent in the presence of multiple
 * threads, the methods are synchronized on the DefaultBindingResolver instance.
 * </p>
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
class DefaultBindingResolver extends BindingResolver {

    /*
     * Holds on binding tables that can be shared by several ASTs.
     */
    static class BindingTables {

        /**
         * This map is used to get a binding from its binding key.
         */
        Map bindingKeysToBindings;
        /**
         * This map is used to keep the correspondence between new bindings and the
         * compiler bindings to their internal counterpart.
         * This is an identity map. We should only create one object for one binding.
         */
        Map compilerBindingsToASTBindings;

        /**
         * This map is used to keep the correspondence between new annotation instances to their internal counterpart.
         * This is an identity map. We should only create one object for one annotation.
         */
        Map compilerAnnotationBindingsToASTBindings;

        BindingTables() {
            this.compilerBindingsToASTBindings = new ConcurrentHashMap();
            this.compilerAnnotationBindingsToASTBindings = new ConcurrentHashMap();
            this.bindingKeysToBindings = new ConcurrentHashMap();
        }

    }

    /**
     * This map is used to retrieve the corresponding block scope for a ast node
     */
    Map astNodesToBlockScope;

    /**
     * This map is used to get an ast node from its binding (new binding) or DOM
     */
    Map bindingsToAstNodes;

    /*
     * The shared binding tables accros ASTs.
     */
    BindingTables bindingTables;

    /**
     * This map is used to retrieve an old ast node using the new ast node. This is not an
     * identity map, as several nested DOM nodes may be associated with the same "larger"
     * compiler AST node.
     * E.g., an ArrayAllocationExpression "new MyType[1]" will appear as the right-hand value
     * for the SimpleType "MyType", the ArrayType "MyType[1]", and the ArrayCreation "new MyType[1]".
     */
    Map newAstToOldAst;

    /**
     * Compilation unit scope
     */
    private CompilationUnitScope scope;

    /**
     * The working copy owner that defines the context in which this resolver is creating the bindings.
     */
    WorkingCopyOwner workingCopyOwner;

    /**
     * Toggle controlling whether DOM bindings should be created when missing internal compiler bindings..
     */
    boolean isRecoveringBindings;

    /**
     * Set to <code>true</code> if initialized from a java project
     */
    boolean fromJavaProject;

    /**
     * Constructor for DefaultBindingResolver.
     */
    DefaultBindingResolver(CompilationUnitScope scope, WorkingCopyOwner workingCopyOwner,
            BindingTables bindingTables, boolean isRecoveringBindings, boolean fromJavaProject) {
        this.newAstToOldAst = new HashMap();
        this.astNodesToBlockScope = new HashMap();
        this.bindingsToAstNodes = new HashMap();
        this.bindingTables = bindingTables;
        this.scope = scope;
        this.workingCopyOwner = workingCopyOwner;
        this.isRecoveringBindings = isRecoveringBindings;
        this.fromJavaProject = fromJavaProject;
    }

    DefaultBindingResolver(LookupEnvironment lookupEnvironment, WorkingCopyOwner workingCopyOwner,
            BindingTables bindingTables, boolean isRecoveringBindings, boolean fromJavaProject) {
        this.newAstToOldAst = new HashMap();
        this.astNodesToBlockScope = new HashMap();
        this.bindingsToAstNodes = new HashMap();
        this.bindingTables = bindingTables;
        this.scope = new CompilationUnitScope(new CompilationUnitDeclaration(null, null, -1), lookupEnvironment);
        this.workingCopyOwner = workingCopyOwner;
        this.isRecoveringBindings = isRecoveringBindings;
        this.fromJavaProject = fromJavaProject;
    }

    @Override
    synchronized ASTNode findDeclaringNode(IBinding binding) {
        if (binding == null) {
            return null;
        }
        if (binding instanceof IMethodBinding) {
            IMethodBinding methodBinding = (IMethodBinding) binding;
            return (ASTNode) this.bindingsToAstNodes.get(methodBinding.getMethodDeclaration());
        } else if (binding instanceof ITypeBinding) {
            ITypeBinding typeBinding = (ITypeBinding) binding;
            return (ASTNode) this.bindingsToAstNodes.get(typeBinding.getTypeDeclaration());
        } else if (binding instanceof IVariableBinding) {
            IVariableBinding variableBinding = (IVariableBinding) binding;
            return (ASTNode) this.bindingsToAstNodes.get(variableBinding.getVariableDeclaration());
        }
        return (ASTNode) this.bindingsToAstNodes.get(binding);
    }

    @Override
    synchronized ASTNode findDeclaringNode(String bindingKey) {
        if (bindingKey == null) {
            return null;
        }
        Object binding = this.bindingTables.bindingKeysToBindings.get(bindingKey);
        if (binding == null)
            return null;
        return (ASTNode) this.bindingsToAstNodes.get(binding);
    }

    IBinding getBinding(org.eclipse.jdt.internal.compiler.lookup.Binding binding) {
        switch (binding.kind()) {
        case Binding.PACKAGE:
            return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
        case Binding.TYPE:
        case Binding.BASE_TYPE:
        case Binding.GENERIC_TYPE:
        case Binding.PARAMETERIZED_TYPE:
        case Binding.RAW_TYPE:
            return getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
        case Binding.ARRAY_TYPE:
        case Binding.TYPE_PARAMETER:
            return new TypeBinding(this, (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
        case Binding.METHOD:
            return getMethodBinding((org.eclipse.jdt.internal.compiler.lookup.MethodBinding) binding);
        case Binding.MODULE:
            return getModuleBinding((org.eclipse.jdt.internal.compiler.lookup.ModuleBinding) binding);
        case Binding.FIELD:
        case Binding.LOCAL:
            return getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding);
        }
        return null;
    }

    Util.BindingsToNodesMap getBindingsToNodesMap() {
        return new Util.BindingsToNodesMap() {
            @Override
            public org.eclipse.jdt.internal.compiler.ast.ASTNode get(Binding binding) {
                return (org.eclipse.jdt.internal.compiler.ast.ASTNode) DefaultBindingResolver.this.newAstToOldAst
                        .get(DefaultBindingResolver.this.bindingsToAstNodes.get(binding));
            }
        };
    }

    @Override
    synchronized org.eclipse.jdt.internal.compiler.ast.ASTNode getCorrespondingNode(ASTNode currentNode) {
        return (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(currentNode);
    }

    @Override
    synchronized IMethodBinding getMethodBinding(
            org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding) {
        return getMethodOrLambdaBinding(methodBinding, null, null);
    }

    private synchronized IMethodBinding getMethodOrLambdaBinding(
            org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding,
            org.eclipse.jdt.internal.compiler.lookup.MethodBinding descriptor, IBinding enclosingBinding) {
        if (methodBinding != null && !methodBinding.isValidBinding()) {
            org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding problemMethodBinding = (org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) methodBinding;
            methodBinding = problemMethodBinding.closestMatch;
        }

        if (methodBinding != null) {
            if (!this.isRecoveringBindings && ((methodBinding.tagBits & TagBits.HasMissingType) != 0)) {
                return null;
            }
            IMethodBinding binding = (IMethodBinding) this.bindingTables.compilerBindingsToASTBindings
                    .get(methodBinding);
            if (binding != null) {
                return binding;
            }
            if (descriptor != null && enclosingBinding != null) {
                binding = new MethodBinding.LambdaMethod(this, descriptor, methodBinding, enclosingBinding);
            } else {
                binding = new MethodBinding(this, methodBinding);
            }
            this.bindingTables.compilerBindingsToASTBindings.put(methodBinding, binding);
            return binding;
        }
        return null;
    }

    @Override
    synchronized IMemberValuePairBinding getMemberValuePairBinding(ElementValuePair valuePair) {
        if (valuePair == null || valuePair.binding == null)
            return null;
        IMemberValuePairBinding binding = (IMemberValuePairBinding) this.bindingTables.compilerBindingsToASTBindings
                .get(valuePair);
        if (binding != null)
            return binding;
        binding = new MemberValuePairBinding(valuePair, this);
        this.bindingTables.compilerBindingsToASTBindings.put(valuePair, binding);
        return binding;
    }

    /**
     * @see org.eclipse.jdt.core.dom.BindingResolver#getModuleBinding(org.eclipse.jdt.internal.compiler.lookup.ModuleBinding)
     */
    @Override
    synchronized IModuleBinding getModuleBinding(
            org.eclipse.jdt.internal.compiler.lookup.ModuleBinding moduleBinding) {
        if (moduleBinding != null) {
            IModuleBinding binding = (IModuleBinding) this.bindingTables.compilerBindingsToASTBindings
                    .get(moduleBinding);
            if (binding == null) {
                binding = new ModuleBinding(this, moduleBinding);
                this.bindingTables.compilerBindingsToASTBindings.put(moduleBinding, binding);
            }
            return binding;
        }
        return null;
    }

    @Override
    synchronized IPackageBinding getPackageBinding(
            org.eclipse.jdt.internal.compiler.lookup.PackageBinding packageBinding) {
        if (packageBinding == null || packageBinding instanceof ProblemPackageBinding) {
            return null;
        }
        IPackageBinding binding = (IPackageBinding) this.bindingTables.compilerBindingsToASTBindings
                .get(packageBinding);
        if (binding != null) {
            return binding;
        }
        binding = packageBinding instanceof ProblemPackageBinding
                ? new RecoveredPackageBinding(packageBinding, this)
                : new PackageBinding(packageBinding, this);
        this.bindingTables.compilerBindingsToASTBindings.put(packageBinding, binding);
        return binding;
    }

    private int getTypeCount(ParameterizedQualifiedTypeReference typeReference) {
        TypeReference[][] typeArguments = typeReference.typeArguments;
        int value = 0;
        org.eclipse.jdt.internal.compiler.ast.Annotation[][] typeAnnotations = typeReference.annotations;
        int length = typeReference.tokens.length;
        for (int i = 0; i < length; ++i) {
            if (value != 0 || (typeArguments != null && typeArguments[i] != null)
                    || (typeAnnotations != null && typeAnnotations[i] != null)) {
                value++;
            }
        }
        return value;
    }

    @Override
    synchronized ITypeBinding getTypeBinding(VariableDeclaration variableDeclaration) {
        ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings
                .get(variableDeclaration);
        if (binding != null) {
            return binding;
        }
        binding = new RecoveredTypeBinding(this, variableDeclaration);
        this.bindingTables.compilerBindingsToASTBindings.put(variableDeclaration, binding);
        return binding;
    }

    @Override
    synchronized ITypeBinding getTypeBinding(Type type) {
        ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings.get(type);
        if (binding != null) {
            return binding;
        }
        binding = new RecoveredTypeBinding(this, type);
        this.bindingTables.compilerBindingsToASTBindings.put(type, binding);
        return binding;
    }

    @Override
    synchronized ITypeBinding getTypeBinding(
            org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding) {
        return internalGetTypeBinding(referenceBinding, null);
    }

    private synchronized ITypeBinding internalGetTypeBinding(
            org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding, IBinding declaringMember) {
        // may also create an TypeBinding.AnonymousTypeBinding
        if (referenceBinding == null) {
            return null;
        } else if (!referenceBinding.isValidBinding()) {
            switch (referenceBinding.problemId()) {
            case ProblemReasons.NotVisible:
            case ProblemReasons.NonStaticReferenceInStaticContext:
                if (referenceBinding instanceof ProblemReferenceBinding) {
                    ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) referenceBinding;
                    org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding2 = problemReferenceBinding
                            .closestMatch();
                    ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings
                            .get(binding2);
                    if (binding != null) {
                        return binding;
                    }
                    binding = TypeBinding.createTypeBinding(this, binding2, declaringMember);
                    this.bindingTables.compilerBindingsToASTBindings.put(binding2, binding);
                    return binding;
                }
                break;
            case ProblemReasons.NotFound:
                if (!this.isRecoveringBindings) {
                    return null;
                }
                ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings
                        .get(referenceBinding);
                if (binding != null) {
                    return binding;
                }
                if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) {
                    binding = TypeBinding.createTypeBinding(this, referenceBinding, declaringMember);
                } else {
                    binding = new RecoveredTypeBinding(this, referenceBinding);
                }
                this.bindingTables.compilerBindingsToASTBindings.put(referenceBinding, binding);
                return binding;
            }
            return null;
        } else {
            if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0 && !this.isRecoveringBindings) {
                return null;
            }
            ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings
                    .get(referenceBinding);
            if (binding != null) {
                return binding;
            }
            binding = TypeBinding.createTypeBinding(this, referenceBinding, declaringMember);
            this.bindingTables.compilerBindingsToASTBindings.put(referenceBinding, binding);
            return binding;
        }
    }

    @Override
    synchronized ITypeBinding getTypeBinding(RecoveredTypeBinding recoveredTypeBinding, int dimensions) {
        if (recoveredTypeBinding == null) {
            return null;
        }
        return new RecoveredTypeBinding(this, recoveredTypeBinding, dimensions);
    }

    synchronized IVariableBinding getVariableBinding(
            org.eclipse.jdt.internal.compiler.lookup.VariableBinding variableBinding,
            VariableDeclaration variableDeclaration) {
        if (this.isRecoveringBindings) {
            if (variableBinding != null) {
                if (variableBinding.isValidBinding()) {
                    IVariableBinding binding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings
                            .get(variableBinding);
                    if (binding != null) {
                        return binding;
                    }
                    if (variableBinding.type != null) {
                        binding = new VariableBinding(this, variableBinding);
                    } else {
                        binding = new RecoveredVariableBinding(this, variableDeclaration);
                    }
                    this.bindingTables.compilerBindingsToASTBindings.put(variableBinding, binding);
                    return binding;
                } else {
                    /*
                     * http://dev.eclipse.org/bugs/show_bug.cgi?id=24449
                     */
                    if (variableBinding instanceof ProblemFieldBinding) {
                        ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) variableBinding;
                        switch (problemFieldBinding.problemId()) {
                        case ProblemReasons.NotVisible:
                        case ProblemReasons.NonStaticReferenceInStaticContext:
                        case ProblemReasons.NonStaticReferenceInConstructorInvocation:
                            ReferenceBinding declaringClass = problemFieldBinding.declaringClass;
                            FieldBinding exactBinding = declaringClass.getField(problemFieldBinding.name,
                                    true /*resolve*/);
                            if (exactBinding != null) {
                                IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings
                                        .get(exactBinding);
                                if (variableBinding2 != null) {
                                    return variableBinding2;
                                }
                                variableBinding2 = new VariableBinding(this, exactBinding);
                                this.bindingTables.compilerBindingsToASTBindings.put(exactBinding,
                                        variableBinding2);
                                return variableBinding2;
                            }
                            break;
                        }
                    }
                }
            }
            return null;
        }
        return this.getVariableBinding(variableBinding);
    }

    @Override
    public WorkingCopyOwner getWorkingCopyOwner() {
        return this.workingCopyOwner;
    }

    @Override
    synchronized IVariableBinding getVariableBinding(
            org.eclipse.jdt.internal.compiler.lookup.VariableBinding variableBinding) {
        if (variableBinding != null) {
            if (variableBinding.isValidBinding()) {
                org.eclipse.jdt.internal.compiler.lookup.TypeBinding variableType = variableBinding.type;
                if (variableType != null) {
                    if (!this.isRecoveringBindings && ((variableType.tagBits & TagBits.HasMissingType) != 0)) {
                        return null;
                    }
                    IVariableBinding binding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings
                            .get(variableBinding);
                    if (binding != null) {
                        return binding;
                    }
                    binding = new VariableBinding(this, variableBinding);
                    this.bindingTables.compilerBindingsToASTBindings.put(variableBinding, binding);
                    return binding;
                }
            } else {
                /*
                 * http://dev.eclipse.org/bugs/show_bug.cgi?id=24449
                 */
                if (variableBinding instanceof ProblemFieldBinding) {
                    ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) variableBinding;
                    switch (problemFieldBinding.problemId()) {
                    case ProblemReasons.NotVisible:
                    case ProblemReasons.NonStaticReferenceInStaticContext:
                    case ProblemReasons.NonStaticReferenceInConstructorInvocation:
                        ReferenceBinding declaringClass = problemFieldBinding.declaringClass;
                        FieldBinding exactBinding = declaringClass.getField(problemFieldBinding.name,
                                true /*resolve*/);
                        if (exactBinding != null) {
                            IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings
                                    .get(exactBinding);
                            if (variableBinding2 != null) {
                                return variableBinding2;
                            }
                            variableBinding2 = new VariableBinding(this, exactBinding);
                            this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding2);
                            return variableBinding2;
                        }
                        break;
                    }
                }
            }
        }
        return null;
    }

    static class AnnotationIdentityBinding {
        org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalInstance;

        AnnotationIdentityBinding(org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalInstance) {
            this.internalInstance = internalInstance;
        }

        @Override
        public boolean equals(Object o) {
            return o instanceof AnnotationIdentityBinding
                    && this.internalInstance == ((AnnotationIdentityBinding) o).internalInstance;
        }

        @Override
        public int hashCode() {
            return this.internalInstance.hashCode();
        }
    }

    @Override
    synchronized IAnnotationBinding getAnnotationInstance(
            org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalInstance) {
        if (internalInstance == null)
            return null;
        ReferenceBinding annotationType = internalInstance.getAnnotationType();
        if (!this.isRecoveringBindings) {
            if (annotationType == null || ((annotationType.tagBits & TagBits.HasMissingType) != 0)) {
                return null;
            }
        }
        Object key = new AnnotationIdentityBinding(internalInstance);
        IAnnotationBinding newDomInstance = new AnnotationBinding(internalInstance, this);
        IAnnotationBinding domInstance = (IAnnotationBinding) ((ConcurrentHashMap) this.bindingTables.compilerAnnotationBindingsToASTBindings)
                .putIfAbsent(key, newDomInstance);
        return domInstance != null ? domInstance : newDomInstance;
    }

    @Override
    boolean isResolvedTypeInferredFromExpectedType(MethodInvocation methodInvocation) {
        Object oldNode = this.newAstToOldAst.get(methodInvocation);
        if (oldNode instanceof MessageSend) {
            MessageSend messageSend = (MessageSend) oldNode;
            org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding = messageSend.binding;
            if (methodBinding instanceof ParameterizedGenericMethodBinding) {
                ParameterizedGenericMethodBinding genericMethodBinding = (ParameterizedGenericMethodBinding) methodBinding;
                return genericMethodBinding.inferredReturnType;
            }
        }
        return false;
    }

    @Override
    boolean isResolvedTypeInferredFromExpectedType(SuperMethodInvocation superMethodInvocation) {
        Object oldNode = this.newAstToOldAst.get(superMethodInvocation);
        if (oldNode instanceof MessageSend) {
            MessageSend messageSend = (MessageSend) oldNode;
            org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding = messageSend.binding;
            if (methodBinding instanceof ParameterizedGenericMethodBinding) {
                ParameterizedGenericMethodBinding genericMethodBinding = (ParameterizedGenericMethodBinding) methodBinding;
                return genericMethodBinding.inferredReturnType;
            }
        }
        return false;
    }

    @Override
    boolean isResolvedTypeInferredFromExpectedType(ClassInstanceCreation classInstanceCreation) {
        Object oldNode = this.newAstToOldAst.get(classInstanceCreation);
        if (oldNode instanceof AllocationExpression) {
            AllocationExpression allocationExpression = (AllocationExpression) oldNode;
            return allocationExpression.inferredReturnType;
        }
        return false;
    }

    @Override
    LookupEnvironment lookupEnvironment() {
        return this.scope.environment();
    }

    /**
     * @see org.eclipse.jdt.core.dom.BindingResolver#recordScope(ASTNode, BlockScope)
     */
    @Override
    synchronized void recordScope(ASTNode astNode, BlockScope blockScope) {
        this.astNodesToBlockScope.put(astNode, blockScope);
    }

    @Override
    boolean resolveBoxing(Expression expression) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(expression);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.Expression
                && ((org.eclipse.jdt.internal.compiler.ast.Expression) node).isTrulyExpression()) {
            org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) node;
            return (compilerExpression.implicitConversion & TypeIds.BOXING) != 0;
        }
        return false;
    }

    @Override
    boolean resolveUnboxing(Expression expression) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(expression);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.Expression) {
            org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) node;
            return (compilerExpression.implicitConversion & TypeIds.UNBOXING) != 0;
        }
        return false;
    }

    @Override
    Object resolveConstantExpressionValue(Expression expression) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(expression);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.Expression
                && ((org.eclipse.jdt.internal.compiler.ast.Expression) node).isTrulyExpression()) {
            org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) node;
            Constant constant = compilerExpression.constant;
            if (constant != null && constant != Constant.NotAConstant) {
                switch (constant.typeID()) {
                case TypeIds.T_int:
                    return Integer.valueOf(constant.intValue());
                case TypeIds.T_byte:
                    return Byte.valueOf(constant.byteValue());
                case TypeIds.T_short:
                    return Short.valueOf(constant.shortValue());
                case TypeIds.T_char:
                    return Character.valueOf(constant.charValue());
                case TypeIds.T_float:
                    return new Float(constant.floatValue());
                case TypeIds.T_double:
                    return new Double(constant.doubleValue());
                case TypeIds.T_boolean:
                    return constant.booleanValue() ? Boolean.TRUE : Boolean.FALSE;
                case TypeIds.T_long:
                    return Long.valueOf(constant.longValue());
                case TypeIds.T_JavaLangString:
                    return constant.stringValue();
                }
                return null;
            }
        }
        return null;
    }

    @Override
    synchronized IMethodBinding resolveConstructor(ClassInstanceCreation expression) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(expression);
        if (node != null && (node.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsAnonymousType) != 0) {
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration anonymousLocalTypeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
            return getMethodBinding(anonymousLocalTypeDeclaration.allocation.binding);
        } else if (node instanceof AllocationExpression) {
            return getMethodBinding(((AllocationExpression) node).binding);
        }
        return null;
    }

    @Override
    synchronized IMethodBinding resolveConstructor(ConstructorInvocation expression) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(expression);
        if (node instanceof ExplicitConstructorCall) {
            ExplicitConstructorCall explicitConstructorCall = (ExplicitConstructorCall) node;
            return getMethodBinding(explicitConstructorCall.binding);
        }
        return null;
    }

    @Override
    IMethodBinding resolveConstructor(EnumConstantDeclaration enumConstantDeclaration) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(enumConstantDeclaration);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node;
            if (fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT
                    && fieldDeclaration.initialization != null) {
                AllocationExpression allocationExpression = (AllocationExpression) fieldDeclaration.initialization;
                return getMethodBinding(allocationExpression.binding);
            }
        }
        return null;
    }

    @Override
    synchronized IMethodBinding resolveConstructor(SuperConstructorInvocation expression) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(expression);
        if (node instanceof ExplicitConstructorCall) {
            ExplicitConstructorCall explicitConstructorCall = (ExplicitConstructorCall) node;
            return getMethodBinding(explicitConstructorCall.binding);
        }
        return null;
    }

    @Override
    synchronized ITypeBinding resolveExpressionType(Expression expression) {
        try {
            switch (expression.getNodeType()) {
            case ASTNode.CLASS_INSTANCE_CREATION:
                org.eclipse.jdt.internal.compiler.ast.ASTNode astNode = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                        .get(expression);
                if (astNode instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
                    // anonymous type case
                    org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) astNode;
                    ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
                    if (typeBinding != null) {
                        return typeBinding;
                    }
                } else if (astNode instanceof AllocationExpression) {
                    // should be an AllocationExpression
                    AllocationExpression allocationExpression = (AllocationExpression) astNode;
                    return this.getTypeBinding(allocationExpression.resolvedType);
                }
                break;
            case ASTNode.SIMPLE_NAME:
            case ASTNode.QUALIFIED_NAME:
                return resolveTypeBindingForName((Name) expression);
            case ASTNode.ARRAY_INITIALIZER:
            case ASTNode.ARRAY_CREATION:
            case ASTNode.ASSIGNMENT:
            case ASTNode.POSTFIX_EXPRESSION:
            case ASTNode.PREFIX_EXPRESSION:
            case ASTNode.CAST_EXPRESSION:
            case ASTNode.TYPE_LITERAL:
            case ASTNode.INFIX_EXPRESSION:
            case ASTNode.INSTANCEOF_EXPRESSION:
            case ASTNode.LAMBDA_EXPRESSION:
            case ASTNode.CREATION_REFERENCE:
            case ASTNode.EXPRESSION_METHOD_REFERENCE:
            case ASTNode.TYPE_METHOD_REFERENCE:
            case ASTNode.SUPER_METHOD_REFERENCE:
            case ASTNode.FIELD_ACCESS:
            case ASTNode.SUPER_FIELD_ACCESS:
            case ASTNode.ARRAY_ACCESS:
            case ASTNode.METHOD_INVOCATION:
            case ASTNode.SUPER_METHOD_INVOCATION:
            case ASTNode.CONDITIONAL_EXPRESSION:
            case ASTNode.SWITCH_EXPRESSION:
            case ASTNode.MARKER_ANNOTATION:
            case ASTNode.NORMAL_ANNOTATION:
            case ASTNode.SINGLE_MEMBER_ANNOTATION:
                org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) this.newAstToOldAst
                        .get(expression);
                if (compilerExpression != null) {
                    return this.getTypeBinding(compilerExpression.resolvedType);
                }
                break;
            case ASTNode.TEXT_BLOCK:
            case ASTNode.STRING_LITERAL:
                if (this.scope != null) {
                    return this.getTypeBinding(this.scope.getJavaLangString());
                }
                break;
            case ASTNode.BOOLEAN_LITERAL:
            case ASTNode.NULL_LITERAL:
            case ASTNode.CHARACTER_LITERAL:
            case ASTNode.NUMBER_LITERAL:
                Literal literal = (Literal) this.newAstToOldAst.get(expression);
                if (literal != null) {
                    return this.getTypeBinding(literal.literalType(null));
                }
                break;
            case ASTNode.THIS_EXPRESSION:
                ThisReference thisReference = (ThisReference) this.newAstToOldAst.get(expression);
                BlockScope blockScope = (BlockScope) this.astNodesToBlockScope.get(expression);
                if (blockScope != null) {
                    return this.getTypeBinding(thisReference.resolveType(blockScope));
                }
                break;
            case ASTNode.PARENTHESIZED_EXPRESSION:
                ParenthesizedExpression parenthesizedExpression = (ParenthesizedExpression) expression;
                return resolveExpressionType(parenthesizedExpression.getExpression());
            case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
                VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression) expression;
                Type type = variableDeclarationExpression.getType();
                if (type != null) {
                    return type.resolveBinding();
                }
                break;
            }
        } catch (AbortCompilation e) {
            // handle missing types
        }
        return null;
    }

    @Override
    synchronized IVariableBinding resolveField(FieldAccess fieldAccess) {
        Object oldNode = this.newAstToOldAst.get(fieldAccess);
        if (oldNode instanceof FieldReference) {
            FieldReference fieldReference = (FieldReference) oldNode;
            return this.getVariableBinding(fieldReference.binding);
        }
        return null;
    }

    @Override
    synchronized IVariableBinding resolveField(SuperFieldAccess fieldAccess) {
        Object oldNode = this.newAstToOldAst.get(fieldAccess);
        if (oldNode instanceof FieldReference) {
            FieldReference fieldReference = (FieldReference) oldNode;
            return this.getVariableBinding(fieldReference.binding);
        }
        return null;
    }

    @Override
    synchronized IBinding resolveImport(ImportDeclaration importDeclaration) {
        if (this.scope == null)
            return null;
        try {
            org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                    .get(importDeclaration);
            if (node instanceof ImportReference) {
                ImportReference importReference = (ImportReference) node;
                final boolean isStatic = importReference.isStatic();
                if ((importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0) {
                    Binding binding = this.scope.getImport(
                            CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length), true,
                            isStatic);
                    if (binding != null) {
                        if (isStatic) {
                            if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                                ITypeBinding typeBinding = this.getTypeBinding(
                                        (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                                return typeBinding == null ? null : typeBinding;
                            }
                        } else {
                            if ((binding.kind() & Binding.PACKAGE) != 0) {
                                IPackageBinding packageBinding = getPackageBinding(
                                        (org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
                                if (packageBinding == null) {
                                    return null;
                                }
                                return packageBinding;
                            } else {
                                // if it is not a package, it has to be a type
                                ITypeBinding typeBinding = this.getTypeBinding(
                                        (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                                if (typeBinding == null) {
                                    return null;
                                }
                                return typeBinding;
                            }
                        }
                    }
                } else {
                    Binding binding = this.scope.getImport(importReference.tokens, false, isStatic);
                    if (binding != null) {
                        if (isStatic) {
                            if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                                ITypeBinding typeBinding = this.getTypeBinding(
                                        (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                                return typeBinding == null ? null : typeBinding;
                            } else if (binding instanceof FieldBinding) {
                                IVariableBinding variableBinding = this.getVariableBinding((FieldBinding) binding);
                                return variableBinding == null ? null : variableBinding;
                            } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding) {
                                // it is a type
                                return getMethodBinding(
                                        (org.eclipse.jdt.internal.compiler.lookup.MethodBinding) binding);
                            }
                        } else {
                            if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                                ITypeBinding typeBinding = this.getTypeBinding(
                                        (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                                return typeBinding == null ? null : typeBinding;
                            }
                        }
                    }
                }
            }
        } catch (AbortCompilation e) {
            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550
            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299
        }
        return null;
    }

    @Override
    IMethodBinding resolveMember(AnnotationTypeMemberDeclaration declaration) {
        Object oldNode = this.newAstToOldAst.get(declaration);
        if (oldNode instanceof AbstractMethodDeclaration) {
            AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) oldNode;
            IMethodBinding methodBinding = getMethodBinding(methodDeclaration.binding);
            if (methodBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(methodBinding, declaration);
            String key = methodBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, methodBinding);
            }
            return methodBinding;
        }
        return null;
    }

    private IVariableBinding[] getSyntheticOuterLocalVariables(
            org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression) {
        IVariableBinding[] syntheticOuterLocals = new IVariableBinding[lambdaExpression.outerLocalVariables.length];
        int i = 0;
        for (SyntheticArgumentBinding sab : lambdaExpression.outerLocalVariables) {
            syntheticOuterLocals[i++] = getVariableBinding(sab);
        }
        return syntheticOuterLocals;
    }

    @Override
    synchronized IMethodBinding resolveMethod(LambdaExpression lambda) {
        Object oldNode = this.newAstToOldAst.get(lambda);
        if (oldNode instanceof org.eclipse.jdt.internal.compiler.ast.LambdaExpression) {
            org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression = (org.eclipse.jdt.internal.compiler.ast.LambdaExpression) oldNode;
            IMethodBinding methodBinding = null;
            if (lambdaExpression.descriptor != null) {
                IBinding declaringMember = getDeclaringMember(lambdaExpression, lambdaExpression.enclosingScope);
                if (declaringMember != null)
                    methodBinding = getMethodOrLambdaBinding(lambdaExpression.getMethodBinding(),
                            lambdaExpression.descriptor, declaringMember);
            }
            if (methodBinding == null) {
                return null;
            }
            if (methodBinding instanceof LambdaMethod) {
                ((LambdaMethod) methodBinding)
                        .setSyntheticOuterLocals(getSyntheticOuterLocalVariables(lambdaExpression));
            }
            this.bindingsToAstNodes.put(methodBinding, lambda);
            String key = methodBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, methodBinding);
            }
            return methodBinding;
        }
        return null;
    }

    private IBinding getDeclaringMember(org.eclipse.jdt.internal.compiler.ast.ASTNode node, Scope currentScope) {
        MethodScope methodScope = currentScope != null ? currentScope.methodScope() : null;
        if (methodScope != null) {
            if (methodScope.isInsideInitializer()) {
                org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingType = methodScope.referenceType();
                if (enclosingType.fields != null) {
                    for (int i = 0; i < enclosingType.fields.length; i++) {
                        FieldDeclaration field = enclosingType.fields[i];
                        if (field.declarationSourceStart <= node.sourceStart
                                && node.sourceEnd <= field.declarationSourceEnd) {
                            if (field instanceof org.eclipse.jdt.internal.compiler.ast.Initializer)
                                return getMethodBinding(((org.eclipse.jdt.internal.compiler.ast.Initializer) field)
                                        .getMethodBinding());
                            else
                                return getVariableBinding(field.binding);
                        }
                    }
                }
            } else {
                if (methodScope.isLambdaScope()) {
                    org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression = (org.eclipse.jdt.internal.compiler.ast.LambdaExpression) methodScope.referenceContext;
                    IMethodBinding methodBinding = null;
                    if (lambdaExpression.descriptor != null) {
                        IBinding declaringMember = getDeclaringMember(lambdaExpression,
                                lambdaExpression.enclosingScope);
                        if (declaringMember != null)
                            methodBinding = getMethodOrLambdaBinding(lambdaExpression.getMethodBinding(),
                                    lambdaExpression.descriptor, declaringMember);
                    }
                    if (methodBinding == null) {
                        return null;
                    }
                    String key = methodBinding.getKey();
                    if (key != null) {
                        this.bindingTables.bindingKeysToBindings.put(key, methodBinding);
                    }
                    return methodBinding;
                } else {
                    return getMethodBinding(methodScope.referenceMethodBinding());
                }
            }
        }
        return null;
    }

    @Override
    synchronized IMethodBinding resolveMethod(MethodDeclaration method) {
        Object oldNode = this.newAstToOldAst.get(method);
        if (oldNode instanceof AbstractMethodDeclaration) {
            AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) oldNode;
            IMethodBinding methodBinding = getMethodBinding(methodDeclaration.binding);
            if (methodBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(methodBinding, method);
            String key = methodBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, methodBinding);
            }
            return methodBinding;
        }
        return null;
    }

    @Override
    synchronized IMethodBinding resolveMethod(MethodInvocation method) {
        Object oldNode = this.newAstToOldAst.get(method);
        if (oldNode instanceof MessageSend) {
            MessageSend messageSend = (MessageSend) oldNode;
            return getMethodBinding(messageSend.binding);
        }
        return null;
    }

    @Override
    synchronized IMethodBinding resolveMethod(MethodReference methodReference) {
        Object oldNode = this.newAstToOldAst.get(methodReference);
        if (oldNode instanceof org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) {
            org.eclipse.jdt.internal.compiler.ast.ReferenceExpression referenceExpression = (org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) oldNode;
            if (referenceExpression.receiverType != null && referenceExpression.receiverType.isArrayType())
                return null;
            IMethodBinding methodBinding = getMethodBinding(referenceExpression.getMethodBinding());
            if (methodBinding == null) {
                return null;
            }
            return methodBinding;
        }
        return null;
    }

    @Override
    synchronized IMethodBinding resolveMethod(SuperMethodInvocation method) {
        Object oldNode = this.newAstToOldAst.get(method);
        if (oldNode instanceof MessageSend) {
            MessageSend messageSend = (MessageSend) oldNode;
            return getMethodBinding(messageSend.binding);
        }
        return null;
    }

    synchronized ITypeBinding resolveTypeBindingForName(Name name) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(name);
        int index = name.index;
        if (node instanceof QualifiedNameReference) {
            QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node;
            final char[][] tokens = qualifiedNameReference.tokens;
            if (tokens.length == index) {
                return this.getTypeBinding(qualifiedNameReference.resolvedType);
            }
            int indexOfFirstFieldBinding = qualifiedNameReference.indexOfFirstFieldBinding; // one-based
            if (index < indexOfFirstFieldBinding) {
                // an extra lookup is required
                BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name);
                Binding binding = null;
                try {
                    if (internalScope == null) {
                        if (this.scope == null)
                            return null;
                        binding = this.scope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index));
                    } else {
                        binding = internalScope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index));
                    }
                } catch (AbortCompilation e) {
                    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550
                    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299
                }
                if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
                    return null;
                } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                    // it is a type
                    return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                }
            } else if (index == indexOfFirstFieldBinding) {
                if (qualifiedNameReference.isTypeReference()) {
                    return this.getTypeBinding(qualifiedNameReference.resolvedType);
                } else {
                    // in this case we want to get the next field declaring's class
                    if (qualifiedNameReference.otherBindings == null) {
                        return null;
                    }
                    FieldBinding fieldBinding = qualifiedNameReference.otherBindings[0];
                    if (fieldBinding == null)
                        return null;
                    org.eclipse.jdt.internal.compiler.lookup.TypeBinding type = fieldBinding.declaringClass;
                    if (type == null) { // array length scenario
                        // use type from first binding (no capture needed for array type)
                        switch (qualifiedNameReference.bits
                                & org.eclipse.jdt.internal.compiler.ast.ASTNode.RestrictiveFlagMASK) {
                        case Binding.FIELD:
                            type = ((FieldBinding) qualifiedNameReference.binding).type;
                            break;
                        case Binding.LOCAL:
                            type = ((LocalVariableBinding) qualifiedNameReference.binding).type;
                            break;
                        }
                    }
                    return this.getTypeBinding(type);
                }
            } else {
                /* This is the case for a name which is part of a qualified name that
                 * cannot be resolved. See PR 13063.
                 */
                if (qualifiedNameReference.otherBindings == null)
                    return null;
                final int otherBindingsLength = qualifiedNameReference.otherBindings.length;
                if (otherBindingsLength == (index - indexOfFirstFieldBinding)) {
                    return this.getTypeBinding(qualifiedNameReference.resolvedType);
                }
                FieldBinding fieldBinding = qualifiedNameReference.otherBindings[index - indexOfFirstFieldBinding];
                if (fieldBinding == null)
                    return null;
                org.eclipse.jdt.internal.compiler.lookup.TypeBinding type = fieldBinding.declaringClass;
                if (type == null) { // array length scenario
                    // use type from previous binding (no capture needed for array type)
                    fieldBinding = qualifiedNameReference.otherBindings[index - indexOfFirstFieldBinding - 1];
                    if (fieldBinding == null)
                        return null;
                    type = fieldBinding.type;
                }
                return this.getTypeBinding(type);
            }
        } else if (node instanceof QualifiedTypeReference) {
            QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference) node;
            if (qualifiedTypeReference.resolvedType == null) {
                return null;
            }
            if (index == qualifiedTypeReference.tokens.length) {
                if (!qualifiedTypeReference.resolvedType.isValidBinding()
                        && qualifiedTypeReference instanceof JavadocQualifiedTypeReference) {
                    JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) node;
                    if (typeRef.packageBinding != null) {
                        return null;
                    }
                }
                return this.getTypeBinding(qualifiedTypeReference.resolvedType.leafComponentType());
            } else {
                if (index >= 0) {
                    BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name);
                    Binding binding = null;
                    try {
                        if (internalScope == null) {
                            if (this.scope == null)
                                return null;
                            binding = this.scope.getTypeOrPackage(
                                    CharOperation.subarray(qualifiedTypeReference.tokens, 0, index));
                        } else {
                            binding = internalScope.getTypeOrPackage(
                                    CharOperation.subarray(qualifiedTypeReference.tokens, 0, index));
                        }
                    } catch (AbortCompilation e) {
                        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    }
                    if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
                        return null;
                    } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                        // it is a type
                        return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                    } else {
                        return null;
                    }
                }
            }
        } else if (node instanceof ImportReference) {
            if ((node.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.inModule) != 0)
                return null;
            ImportReference importReference = (ImportReference) node;
            int importReferenceLength = importReference.tokens.length;
            if (index >= 0) {
                Binding binding = null;
                if (this.scope == null)
                    return null;
                if (importReferenceLength == index) {
                    try {
                        binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index),
                                (importReference.bits
                                        & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0,
                                importReference.isStatic());
                    } catch (AbortCompilation e) {
                        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    }
                } else {
                    try {
                        binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index),
                                true, importReference.isStatic());
                    } catch (AbortCompilation e) {
                        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    }
                }
                if (binding != null) {
                    if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                        // it is a type
                        return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                    }
                    return null;
                }
            }
        } else if (node instanceof AbstractMethodDeclaration) {
            AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node;
            IMethodBinding method = getMethodBinding(methodDeclaration.binding);
            if (method == null)
                return null;
            return method.getReturnType();
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
            ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
            if (typeBinding != null) {
                return typeBinding;
            }
        }
        if (node instanceof JavadocSingleNameReference) {
            JavadocSingleNameReference singleNameReference = (JavadocSingleNameReference) node;
            LocalVariableBinding localVariable = (LocalVariableBinding) singleNameReference.binding;
            if (localVariable != null) {
                return this.getTypeBinding(localVariable.type);
            }
        }
        if (node instanceof SingleNameReference) {
            SingleNameReference singleNameReference = (SingleNameReference) node;
            return this.getTypeBinding(singleNameReference.resolvedType);
        } else if (node instanceof QualifiedSuperReference) {
            QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) node;
            return this.getTypeBinding(qualifiedSuperReference.qualification.resolvedType);
        } else if (node instanceof Receiver) {
            org.eclipse.jdt.internal.compiler.lookup.TypeBinding receiver = ((Receiver) node).type.resolvedType;
            return this.getTypeBinding(receiver);
        } else if (node instanceof LocalDeclaration) {
            IVariableBinding variable = this.getVariableBinding(((LocalDeclaration) node).binding);
            if (variable == null)
                return null;
            return variable.getType();
        } else if (node instanceof JavadocFieldReference) {
            JavadocFieldReference fieldRef = (JavadocFieldReference) node;
            if (fieldRef.methodBinding != null) {
                return getMethodBinding(fieldRef.methodBinding).getReturnType();
            }
            return getTypeBinding(fieldRef.resolvedType);
        } else if (node instanceof FieldReference) {
            return getTypeBinding(((FieldReference) node).resolvedType);
        } else if (node instanceof SingleTypeReference) {
            SingleTypeReference singleTypeReference = (SingleTypeReference) node;
            org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding = singleTypeReference.resolvedType;
            if (binding != null) {
                return this.getTypeBinding(binding.leafComponentType());
            }
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node;
            IVariableBinding field = this.getVariableBinding(fieldDeclaration.binding);
            if (field == null)
                return null;
            return field.getType();
        } else if (node instanceof MessageSend) {
            MessageSend messageSend = (MessageSend) node;
            IMethodBinding method = getMethodBinding(messageSend.binding);
            if (method == null)
                return null;
            return method.getReturnType();
        } else if (node instanceof AllocationExpression) {
            AllocationExpression allocation = (AllocationExpression) node;
            return getTypeBinding(allocation.resolvedType);
        } else if (node instanceof JavadocImplicitTypeReference) {
            JavadocImplicitTypeReference implicitRef = (JavadocImplicitTypeReference) node;
            return getTypeBinding(implicitRef.resolvedType);
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeParameter) {
            org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter = (org.eclipse.jdt.internal.compiler.ast.TypeParameter) node;
            return this.getTypeBinding(typeParameter.binding);
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.MemberValuePair) {
            org.eclipse.jdt.internal.compiler.ast.MemberValuePair memberValuePair = (org.eclipse.jdt.internal.compiler.ast.MemberValuePair) node;
            IMethodBinding method = getMethodBinding(memberValuePair.binding);
            if (method == null)
                return null;
            return method.getReturnType();
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) {
            org.eclipse.jdt.internal.compiler.ast.ReferenceExpression referenceExpression = (org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) node;
            IMethodBinding method = getMethodBinding(referenceExpression.getMethodBinding());
            if (method == null)
                return null;
            return method.getReturnType();
        }
        return null;
    }

    @Override
    synchronized IBinding resolveName(Name name) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(name);
        int index = name.index;
        if (node instanceof QualifiedNameReference) {
            QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node;
            final char[][] tokens = qualifiedNameReference.tokens;
            int indexOfFirstFieldBinding = qualifiedNameReference.indexOfFirstFieldBinding; // one-based
            if (index < indexOfFirstFieldBinding) {
                // an extra lookup is required
                BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name);
                Binding binding = null;
                try {
                    if (internalScope == null) {
                        if (this.scope == null)
                            return null;
                        binding = this.scope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index));
                    } else {
                        binding = internalScope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index));
                    }
                } catch (AbortCompilation e) {
                    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550
                    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299
                }
                if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
                    return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
                } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                    // it is a type
                    return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                }
            } else if (index == indexOfFirstFieldBinding) {
                if (qualifiedNameReference.isTypeReference()) {
                    return this.getTypeBinding(qualifiedNameReference.resolvedType);
                } else {
                    Binding binding = qualifiedNameReference.binding;
                    if (binding != null) {
                        if (binding.isValidBinding()) {
                            return this.getVariableBinding(
                                    (org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding);
                        } else if (binding instanceof ProblemFieldBinding) {
                            ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) binding;
                            switch (problemFieldBinding.problemId()) {
                            case ProblemReasons.NotVisible:
                            case ProblemReasons.NonStaticReferenceInStaticContext:
                                ReferenceBinding declaringClass = problemFieldBinding.declaringClass;
                                if (declaringClass != null) {
                                    FieldBinding exactBinding = declaringClass.getField(tokens[tokens.length - 1],
                                            true /*resolve*/);
                                    if (exactBinding != null) {
                                        if (exactBinding.type != null) {
                                            IVariableBinding variableBinding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings
                                                    .get(exactBinding);
                                            if (variableBinding != null) {
                                                return variableBinding;
                                            }
                                            variableBinding = new VariableBinding(this, exactBinding);
                                            this.bindingTables.compilerBindingsToASTBindings.put(exactBinding,
                                                    variableBinding);
                                            return variableBinding;
                                        }
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            } else {
                /* This is the case for a name which is part of a qualified name that
                 * cannot be resolved. See PR 13063.
                 */
                if (qualifiedNameReference.otherBindings == null || (index - indexOfFirstFieldBinding - 1) < 0) {
                    return null;
                } else {
                    return this.getVariableBinding(
                            qualifiedNameReference.otherBindings[index - indexOfFirstFieldBinding - 1]);
                }
            }
        } else if (node instanceof QualifiedTypeReference) {
            QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference) node;
            if (qualifiedTypeReference.resolvedType == null) {
                return null;
            }
            if (index == qualifiedTypeReference.tokens.length) {
                if (!qualifiedTypeReference.resolvedType.isValidBinding()
                        && qualifiedTypeReference instanceof JavadocQualifiedTypeReference) {
                    JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) node;
                    if (typeRef.packageBinding != null) {
                        return getPackageBinding(typeRef.packageBinding);
                    }
                }
                return this.getTypeBinding(qualifiedTypeReference.resolvedType.leafComponentType());
            } else {
                if (index >= 0) {
                    BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name);
                    Binding binding = null;
                    try {
                        if (internalScope == null) {
                            if (this.scope == null)
                                return null;
                            binding = this.scope.getTypeOrPackage(
                                    CharOperation.subarray(qualifiedTypeReference.tokens, 0, index));
                        } else {
                            binding = internalScope.getTypeOrPackage(
                                    CharOperation.subarray(qualifiedTypeReference.tokens, 0, index));
                        }
                    } catch (AbortCompilation e) {
                        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    }
                    if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
                        return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
                    } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                        // it is a type
                        return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                    } else {
                        return null;
                    }
                }
            }
        } else if (node instanceof ImportReference) {
            ImportReference importReference = (ImportReference) node;
            int importReferenceLength = importReference.tokens.length;
            boolean inModule = (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.inModule) != 0;
            if (index >= 0) {
                Binding binding = null;
                if (this.scope == null)
                    return null;
                if (importReferenceLength == index && !inModule) {
                    try {
                        binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index),
                                (importReference.bits
                                        & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0,
                                importReference.isStatic());
                    } catch (AbortCompilation e) {
                        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    }
                } else {
                    try {
                        binding = this.scope.getImport(
                                inModule ? importReference.tokens
                                        : CharOperation.subarray(importReference.tokens, 0, index),
                                true, importReference.isStatic());
                    } catch (AbortCompilation e) {
                        // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
                    }
                }
                if (binding != null) {
                    if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
                        return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
                    } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
                        // it is a type
                        return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding);
                    } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.FieldBinding) {
                        // it is a type
                        return this.getVariableBinding(
                                (org.eclipse.jdt.internal.compiler.lookup.FieldBinding) binding);
                    } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding) {
                        // it is a type
                        return getMethodBinding((org.eclipse.jdt.internal.compiler.lookup.MethodBinding) binding);
                    } else {
                        return null;
                    }
                }
            }
        } else if (node instanceof CompilationUnitDeclaration) {
            CompilationUnitDeclaration compilationUnitDeclaration = (CompilationUnitDeclaration) node;
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
            if (types == null || types.length == 0) {
                return null;
            }
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration type = types[0];
            if (type != null) {
                ITypeBinding typeBinding = this.getTypeBinding(type.binding);
                if (typeBinding != null) {
                    return typeBinding.getPackage();
                }
            }
        } else if (node instanceof AbstractMethodDeclaration) {
            AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node;
            IMethodBinding methodBinding = getMethodBinding(methodDeclaration.binding);
            if (methodBinding != null) {
                return methodBinding;
            }
        } else if (node instanceof ModuleReference) {
            ModuleReference moduleReference = (ModuleReference) node;
            IModuleBinding moduleBinding = getModuleBinding(moduleReference.binding);
            if (moduleBinding != null) {
                return moduleBinding;
            }
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration moduleDeclaration = (org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration) node;
            IModuleBinding moduleBinding = getModuleBinding(moduleDeclaration.binding);
            if (moduleBinding != null) {
                return moduleBinding;
            }
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
            ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
            if (typeBinding != null) {
                return typeBinding;
            }
        }
        if (node instanceof SingleNameReference) {
            SingleNameReference singleNameReference = (SingleNameReference) node;
            if (singleNameReference.isTypeReference()) {
                return this.getTypeBinding(singleNameReference.resolvedType);
            } else {
                // this is a variable or a field
                Binding binding = singleNameReference.binding;
                if (binding != null) {
                    if (binding.isValidBinding()) {
                        return this.getVariableBinding(
                                (org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding);
                    } else {
                        /*
                         * http://dev.eclipse.org/bugs/show_bug.cgi?id=24449
                         */
                        if (binding instanceof ProblemFieldBinding) {
                            ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) binding;
                            switch (problemFieldBinding.problemId()) {
                            case ProblemReasons.NotVisible:
                            case ProblemReasons.NonStaticReferenceInStaticContext:
                            case ProblemReasons.NonStaticReferenceInConstructorInvocation:
                                ReferenceBinding declaringClass = problemFieldBinding.declaringClass;
                                FieldBinding exactBinding = declaringClass.getField(problemFieldBinding.name,
                                        true /*resolve*/);
                                if (exactBinding != null) {
                                    if (exactBinding.type != null) {
                                        IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings
                                                .get(exactBinding);
                                        if (variableBinding2 != null) {
                                            return variableBinding2;
                                        }
                                        variableBinding2 = new VariableBinding(this, exactBinding);
                                        this.bindingTables.compilerBindingsToASTBindings.put(exactBinding,
                                                variableBinding2);
                                        return variableBinding2;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
        } else if (node instanceof QualifiedSuperReference) {
            QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) node;
            return this.getTypeBinding(qualifiedSuperReference.qualification.resolvedType);
        } else if (node instanceof LocalDeclaration) {
            return name.getAST().apiLevel() >= AST.JLS10_INTERNAL && name instanceof SimpleName
                    && ((SimpleName) name).isVar() ? resolveTypeBindingForName(name)
                            : this.getVariableBinding(((LocalDeclaration) node).binding);
        } else if (node instanceof JavadocFieldReference) {
            JavadocFieldReference fieldRef = (JavadocFieldReference) node;
            if (fieldRef.methodBinding != null) {
                return getMethodBinding(fieldRef.methodBinding);
            }
            return getVariableBinding(fieldRef.binding);
        } else if (node instanceof FieldReference) {
            return getVariableBinding(((FieldReference) node).binding);
        } else if (node instanceof SingleTypeReference) {
            if (node instanceof JavadocSingleTypeReference) {
                JavadocSingleTypeReference typeRef = (JavadocSingleTypeReference) node;
                if (typeRef.packageBinding != null) {
                    return getPackageBinding(typeRef.packageBinding);
                }
            }
            SingleTypeReference singleTypeReference = (SingleTypeReference) node;
            org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding = singleTypeReference.resolvedType;
            if (binding == null) {
                return null;
            }
            return this.getTypeBinding(binding.leafComponentType());
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node;
            return this.getVariableBinding(fieldDeclaration.binding);
        } else if (node instanceof MessageSend) {
            MessageSend messageSend = (MessageSend) node;
            return getMethodBinding(messageSend.binding);
        } else if (node instanceof AllocationExpression) {
            AllocationExpression allocation = (AllocationExpression) node;
            return getMethodBinding(allocation.binding);
        } else if (node instanceof JavadocImplicitTypeReference) {
            JavadocImplicitTypeReference implicitRef = (JavadocImplicitTypeReference) node;
            return getTypeBinding(implicitRef.resolvedType);
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeParameter) {
            org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter = (org.eclipse.jdt.internal.compiler.ast.TypeParameter) node;
            return this.getTypeBinding(typeParameter.binding);
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.MemberValuePair) {
            org.eclipse.jdt.internal.compiler.ast.MemberValuePair memberValuePair = (org.eclipse.jdt.internal.compiler.ast.MemberValuePair) node;
            return getMethodBinding(memberValuePair.binding);
        } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) {
            org.eclipse.jdt.internal.compiler.ast.ReferenceExpression referenceExpression = (org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) node;
            return getMethodBinding(referenceExpression.getMethodBinding());
        }
        return null;
    }

    @Override
    synchronized IPackageBinding resolvePackage(PackageDeclaration pkg) {
        if (this.scope == null)
            return null;
        try {
            org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                    .get(pkg);
            if (node instanceof ImportReference) {
                ImportReference importReference = (ImportReference) node;
                Binding binding = this.scope.getOnlyPackage(
                        CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length));
                if ((binding != null) && (binding.isValidBinding())) {
                    if (binding instanceof ReferenceBinding) {
                        // this only happens if a type name has the same name as its package
                        ReferenceBinding referenceBinding = (ReferenceBinding) binding;
                        binding = referenceBinding.fPackage;
                    }
                    if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) {
                        IPackageBinding packageBinding = getPackageBinding(
                                (org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding);
                        if (packageBinding == null) {
                            return null;
                        }
                        this.bindingsToAstNodes.put(packageBinding, pkg);
                        String key = packageBinding.getKey();
                        if (key != null) {
                            this.bindingTables.bindingKeysToBindings.put(key, packageBinding);
                        }
                        return packageBinding;
                    }
                }
            }
        } catch (AbortCompilation e) {
            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550
            // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299
        }
        return null;
    }

    @Override
    synchronized IBinding resolveReference(MemberRef ref) {
        org.eclipse.jdt.internal.compiler.ast.Expression expression = (org.eclipse.jdt.internal.compiler.ast.Expression) this.newAstToOldAst
                .get(ref);
        if (expression instanceof TypeReference) {
            return getTypeBinding(expression.resolvedType);
        } else if (expression instanceof JavadocFieldReference) {
            JavadocFieldReference fieldRef = (JavadocFieldReference) expression;
            if (fieldRef.methodBinding != null) {
                return getMethodBinding(fieldRef.methodBinding);
            }
            return getVariableBinding(fieldRef.binding);
        }
        return null;
    }

    @Override
    synchronized IMemberValuePairBinding resolveMemberValuePair(
            org.eclipse.jdt.core.dom.MemberValuePair memberValuePair) {
        MemberValuePair valuePair = (MemberValuePair) this.newAstToOldAst.get(memberValuePair);
        if (valuePair != null) {
            return getMemberValuePairBinding(valuePair.compilerElementPair);
        }
        return null;
    }

    /**
     * @see BindingResolver#resolveModule(ModuleDeclaration)
     * @since 3.14   
     */
    @Override
    IModuleBinding resolveModule(ModuleDeclaration module) {
        Object oldNode = this.newAstToOldAst.get(module);
        if (oldNode instanceof org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration moduleDeclaration = (org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration) oldNode;
            IModuleBinding moduleBinding = getModuleBinding(moduleDeclaration.binding);
            if (moduleBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(moduleBinding, module);
            String key = moduleBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, moduleBinding);
            }
            return moduleBinding;
        }

        return null;
    }

    @Override
    synchronized IBinding resolveReference(MethodRef ref) {
        org.eclipse.jdt.internal.compiler.ast.Expression expression = (org.eclipse.jdt.internal.compiler.ast.Expression) this.newAstToOldAst
                .get(ref);
        if (expression instanceof JavadocMessageSend) {
            return getMethodBinding(((JavadocMessageSend) expression).binding);
        } else if (expression instanceof JavadocAllocationExpression) {
            return getMethodBinding(((JavadocAllocationExpression) expression).binding);
        }
        return null;
    }

    @Override
    ITypeBinding resolveType(AnnotationTypeDeclaration type) {
        final Object node = this.newAstToOldAst.get(type);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
            ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
            if (typeBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(typeBinding, type);
            String key = typeBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, typeBinding);
            }
            return typeBinding;
        }
        return null;
    }

    @Override
    synchronized ITypeBinding resolveType(AnonymousClassDeclaration type) {
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(type);
        if (node != null && (node.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsAnonymousType) != 0) {
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration anonymousLocalTypeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
            IBinding declaringMember = getDeclaringMember(anonymousLocalTypeDeclaration,
                    anonymousLocalTypeDeclaration.scope);
            ITypeBinding typeBinding = internalGetTypeBinding(anonymousLocalTypeDeclaration.binding,
                    declaringMember);
            if (typeBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(typeBinding, type);
            String key = typeBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, typeBinding);
            }
            return typeBinding;
        }
        return null;
    }

    @Override
    ITypeBinding resolveType(EnumDeclaration type) {
        final Object node = this.newAstToOldAst.get(type);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
            ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
            if (typeBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(typeBinding, type);
            String key = typeBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, typeBinding);
            }
            return typeBinding;
        }
        return null;
    }

    @Override
    synchronized ITypeBinding resolveType(Type type) {
        // retrieve the old ast node
        org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst
                .get(type);
        org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding = null;
        if (type.getAST().apiLevel() >= AST.JLS10_INTERNAL && type.isVar()) {
            return resolveTypeBindingForName(((SimpleType) type).getName());
        }
        if (node != null) {
            if (node instanceof Receiver) {
                node = ((Receiver) node).type;
            }
            if (node instanceof ParameterizedQualifiedTypeReference) {
                ParameterizedQualifiedTypeReference typeReference = (ParameterizedQualifiedTypeReference) node;
                org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding = typeReference.resolvedType;
                // This unlikely case is possible when for some reason binding resolution has been stopped, like duplicate type declaration (bug 376440)
                if (typeBinding == null)
                    return null;
                if (type.isArrayType()) {
                    if (this.scope == null) {
                        return null;
                    }
                    ArrayType arrayType = (ArrayType) type;
                    ArrayBinding arrayBinding = (ArrayBinding) typeBinding;
                    int dimensions = arrayType.getDimensions();
                    boolean isVarargs = typeReference.isVarargs();
                    if (dimensions == arrayBinding.dimensions)
                        return getTypeBinding(arrayBinding); // reuse.
                    return getTypeBinding(this.scope.createArrayType(arrayBinding.leafComponentType, dimensions,
                            getTypeAnnotations(dimensions, arrayBinding, isVarargs)));
                }
                if (typeBinding.isArrayType()) {
                    // 'typeBinding' can still be an array type because 'node' may be "larger" than 'type' (see comment of newAstToOldAst).
                    typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
                }
                int index;
                if (type.isQualifiedType()) {
                    index = ((QualifiedType) type).index;
                } else if (type.isParameterizedType()) {
                    index = ((ParameterizedType) type).index;
                } else {
                    index = 1;
                }
                final int numberOfTypeArgumentsNotNull = getTypeCount(typeReference);
                if (index != numberOfTypeArgumentsNotNull) {
                    int i = numberOfTypeArgumentsNotNull;
                    while (i != index) {
                        typeBinding = typeBinding.enclosingType();
                        i--;
                    }
                    binding = typeBinding;
                } else {
                    binding = typeBinding;
                }
            } else if (node instanceof TypeReference) {
                if (type instanceof SimpleType && node instanceof QualifiedTypeReference) {
                    return resolveTypeBindingForName(((SimpleType) type).getName());
                } else if (type instanceof QualifiedType) {
                    return resolveTypeBindingForName(((QualifiedType) type).getName());
                } else if (type instanceof NameQualifiedType) {
                    return resolveTypeBindingForName(((NameQualifiedType) type).getName());
                }
                TypeReference typeReference = (TypeReference) node;
                binding = typeReference.resolvedType;
            } else if (node instanceof SingleNameReference && ((SingleNameReference) node).isTypeReference()) {
                binding = (((SingleNameReference) node).resolvedType);
            } else if (node instanceof QualifiedNameReference
                    && ((QualifiedNameReference) node).isTypeReference()) {
                binding = (((QualifiedNameReference) node).resolvedType);
            } else if (node instanceof ArrayAllocationExpression) {
                binding = ((ArrayAllocationExpression) node).resolvedType;
            }
            if (binding != null) {
                if (type.isArrayType()) {
                    ArrayType arrayType = (ArrayType) type;
                    if (this.scope == null) {
                        return null;
                    }
                    ArrayBinding arrayBinding = (ArrayBinding) binding;
                    int dimensions = arrayType.getDimensions();
                    boolean isVarargs = node instanceof TypeReference && ((TypeReference) node).isVarargs();
                    if (dimensions == arrayBinding.dimensions)
                        return getTypeBinding(arrayBinding); // reuse
                    return getTypeBinding(this.scope.createArrayType(arrayBinding.leafComponentType, dimensions,
                            getTypeAnnotations(dimensions, arrayBinding, isVarargs)));
                } else if (binding.isArrayType()) {
                    // 'binding' can still be an array type because 'node' may be "larger" than 'type' (see comment of newAstToOldAst).
                    ArrayBinding arrayBinding = (ArrayBinding) binding;
                    return getTypeBinding(arrayBinding.leafComponentType);
                }
                return getTypeBinding(binding);
            }
        } else if (type.isPrimitiveType()) {
            /* Handle the void primitive type returned by getReturnType for a method declaration
             * that is a constructor declaration. It prevents null from being returned
             */
            if (((PrimitiveType) type).getPrimitiveTypeCode() == PrimitiveType.VOID) {
                return this.getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding.VOID);
            }
        }
        return null;
    }

    private org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] getTypeAnnotations(int dimensions,
            ArrayBinding arrayBinding, boolean isVarargs) {
        org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] oldies = arrayBinding.getTypeAnnotations();
        org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] newbies = Binding.NO_ANNOTATIONS;
        // Skip past extended dimensions encoded ahead of base dimensions. Dimension for variable argument array comes after the base dimensions.
        int extendedDimensions = arrayBinding.dimensions - dimensions - (isVarargs ? 1 : 0);
        int i, length;
        for (i = 0, length = oldies == null ? 0 : oldies.length; i < length && extendedDimensions > 0; i++) {
            if (oldies[i] == null)
                extendedDimensions--;
        }
        int cells = 0;
        for (int j = i; j < length && dimensions > 0; j++) {
            if (oldies[j] == null)
                dimensions--;
            cells++;
        }
        if (cells > 0)
            System.arraycopy(oldies, i,
                    newbies = new org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[cells], 0, cells);
        return newbies;
    }

    @Override
    synchronized ITypeBinding resolveType(TypeDeclaration type) {
        final Object node = this.newAstToOldAst.get(type);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
            IBinding declaringMember = getDeclaringMember(typeDeclaration, typeDeclaration.scope);
            ITypeBinding typeBinding = internalGetTypeBinding(typeDeclaration.binding, declaringMember);
            if (typeBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(typeBinding, type);
            String key = typeBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, typeBinding);
            }
            return typeBinding;
        }
        return null;
    }

    @Override
    synchronized ITypeBinding resolveTypeParameter(TypeParameter typeParameter) {
        final Object node = this.newAstToOldAst.get(typeParameter);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeParameter) {
            org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter2 = (org.eclipse.jdt.internal.compiler.ast.TypeParameter) node;
            ITypeBinding typeBinding = this.getTypeBinding(typeParameter2.binding);
            if (typeBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(typeBinding, typeParameter);
            String key = typeBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, typeBinding);
            }
            return typeBinding;
        }
        return null;
    }

    @Override
    synchronized IVariableBinding resolveVariable(EnumConstantDeclaration enumConstant) {
        final Object node = this.newAstToOldAst.get(enumConstant);
        if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) {
            org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node;
            IVariableBinding variableBinding = this.getVariableBinding(fieldDeclaration.binding);
            if (variableBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(variableBinding, enumConstant);
            String key = variableBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, variableBinding);
            }
            return variableBinding;
        }
        return null;
    }

    @Override
    synchronized IVariableBinding resolveVariable(VariableDeclaration variable) {
        final Object node = this.newAstToOldAst.get(variable);
        if (node instanceof AbstractVariableDeclaration) {
            AbstractVariableDeclaration abstractVariableDeclaration = (AbstractVariableDeclaration) node;
            IVariableBinding variableBinding = null;
            if (abstractVariableDeclaration instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) {
                org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) abstractVariableDeclaration;
                variableBinding = this.getVariableBinding(fieldDeclaration.binding, variable);
            } else {
                variableBinding = this.getVariableBinding(((LocalDeclaration) abstractVariableDeclaration).binding,
                        variable);
            }
            if (variableBinding == null) {
                return null;
            }
            this.bindingsToAstNodes.put(variableBinding, variable);
            String key = variableBinding.getKey();
            if (key != null) {
                this.bindingTables.bindingKeysToBindings.put(key, variableBinding);
            }
            return variableBinding;
        }
        return null;
    }

    @Override
    synchronized ITypeBinding resolveWellKnownType(String name) {
        if (this.scope == null)
            return null;
        ITypeBinding typeBinding = null;
        try {
            if (("boolean".equals(name))//$NON-NLS-1$
                    || ("char".equals(name))//$NON-NLS-1$
                    || ("byte".equals(name))//$NON-NLS-1$
                    || ("short".equals(name))//$NON-NLS-1$
                    || ("int".equals(name))//$NON-NLS-1$
                    || ("long".equals(name))//$NON-NLS-1$
                    || ("float".equals(name))//$NON-NLS-1$
                    || ("double".equals(name))//$NON-NLS-1$
                    || ("void".equals(name))) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(Scope.getBaseType(name.toCharArray()));
            } else if ("java.lang.Object".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getJavaLangObject());
            } else if ("java.lang.String".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getJavaLangString());
            } else if ("java.lang.StringBuffer".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_STRINGBUFFER, 3));
            } else if ("java.lang.Throwable".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getJavaLangThrowable());
            } else if ("java.lang.Exception".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_EXCEPTION, 3));
            } else if ("java.lang.RuntimeException".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, 3));
            } else if ("java.lang.Error".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_ERROR, 3));
            } else if ("java.lang.Class".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getJavaLangClass());
            } else if ("java.lang.Cloneable".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getJavaLangCloneable());
            } else if ("java.io.Serializable".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getJavaIoSerializable());
            } else if ("java.lang.Boolean".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_BOOLEAN, 3));
            } else if ("java.lang.Byte".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_BYTE, 3));
            } else if ("java.lang.Character".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_CHARACTER, 3));
            } else if ("java.lang.Double".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_DOUBLE, 3));
            } else if ("java.lang.Float".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_FLOAT, 3));
            } else if ("java.lang.Integer".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_INTEGER, 3));
            } else if ("java.lang.Long".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_LONG, 3));
            } else if ("java.lang.Short".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_SHORT, 3));
            } else if ("java.lang.Void".equals(name)) {//$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_VOID, 3));
            } else if ("java.lang.AssertionError".equals(name)) { //$NON-NLS-1$
                typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_ASSERTIONERROR, 3));
            }
        } catch (AbortCompilation e) {
            // ignore missing types
        }
        if (typeBinding != null && !typeBinding.isRecovered()) {
            return typeBinding;
        }
        return null;
    }

    @Override
    synchronized IAnnotationBinding resolveAnnotation(final Annotation domASTNode) {
        Object oldNode = this.newAstToOldAst.get(domASTNode);
        if (oldNode instanceof org.eclipse.jdt.internal.compiler.ast.Annotation) {
            org.eclipse.jdt.internal.compiler.ast.Annotation internalAstNode = (org.eclipse.jdt.internal.compiler.ast.Annotation) oldNode;

            IAnnotationBinding domAnnotation = getAnnotationInstance(internalAstNode.getCompilerAnnotation());
            if (domAnnotation == null)
                return null;
            this.bindingsToAstNodes.put(domAnnotation, domASTNode);
            return domAnnotation;
        }
        return null;
    }

    @Override
    public CompilationUnitScope scope() {
        return this.scope;
    }

    @Override
    synchronized void store(ASTNode node, org.eclipse.jdt.internal.compiler.ast.ASTNode oldASTNode) {
        this.newAstToOldAst.put(node, oldASTNode);
    }

    @Override
    synchronized void updateKey(ASTNode node, ASTNode newNode) {
        Object astNode = this.newAstToOldAst.remove(node);
        if (astNode != null) {
            this.newAstToOldAst.put(newNode, astNode);
        }
    }

    @Override
    ITypeBinding resolveArrayType(ITypeBinding typeBinding, int dimensions) {
        if (typeBinding instanceof RecoveredTypeBinding)
            throw new IllegalArgumentException("Cannot be called on a recovered type binding"); //$NON-NLS-1$
        ITypeBinding leafComponentType = typeBinding;
        int actualDimensions = dimensions;
        if (typeBinding.isArray()) {
            leafComponentType = typeBinding.getElementType();
            actualDimensions += typeBinding.getDimensions();
        }
        if (!(leafComponentType instanceof TypeBinding))
            return null;
        org.eclipse.jdt.internal.compiler.lookup.TypeBinding leafTypeBinding = ((TypeBinding) leafComponentType).binding;
        if (leafTypeBinding instanceof VoidTypeBinding) {
            throw new IllegalArgumentException();
        }
        if (typeBinding.isArray()) {
            return this.getTypeBinding(lookupEnvironment().createArrayType(leafTypeBinding, actualDimensions,
                    insertAnnotations((((TypeBinding) typeBinding).binding).getTypeAnnotations(), dimensions)));
        } else {
            return this.getTypeBinding(lookupEnvironment().createArrayType(leafTypeBinding, actualDimensions));
        }
    }

    private org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] insertAnnotations(
            org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] annots, int dimensions) {
        if (dimensions == 0 || annots == null || annots.length == 0) {
            return annots;
        }
        int index = 0;
        if (dimensions < 0) {
            for (int i = 0; i < annots.length; i++) {
                index++;
                if (annots[i] == null) {
                    if (++dimensions == 0)
                        break;
                }
            }
            if (dimensions < 0)
                dimensions = 0; // Just means there were no annotations
        }
        org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] newAnnots = new org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[annots.length
                - index + dimensions];

        System.arraycopy(annots, index, newAnnots, dimensions, annots.length - index);
        return newAnnots;
    }
}