gt:             if (thrownExceptions.size() == 1) {
context: /**
   * ***************************************************************************** Copyright (c) 2000,
   * 2014 IBM Corporation and others. All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0 which accompanies this
   * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
   *
   * <p>Contributors: IBM Corporation - initial API and implementation
   * *****************************************************************************
   */
  package org.eclipse.jdt.internal.ui.text.correction;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.jdt.core.ICompilationUnit;
  import org.eclipse.jdt.core.JavaModelException;
  import org.eclipse.jdt.core.dom.*;
  import org.eclipse.jdt.core.dom.PrimitiveType.Code;
  import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
  import org.eclipse.jdt.internal.corext.dom.ASTNodes;
  import org.eclipse.jdt.internal.corext.dom.Bindings;
  import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
  import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
  import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor;
  import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
  import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
  import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
  import org.eclipse.jdt.ui.JavaElementLabels;
  
  /** JDT-UI-internal helper methods to find AST nodes or bindings. */
  public class ASTResolving {
  
    public static ITypeBinding guessBindingForReference(ASTNode node) {
      return Bindings.normalizeTypeBinding(getPossibleReferenceBinding(node));
    }
  
    private static ITypeBinding getPossibleReferenceBinding(ASTNode node) {
      ASTNode parent = node.getParent();
      switch (parent.getNodeType()) {
        case ASTNode.ASSIGNMENT:
          Assignment assignment = (Assignment) parent;
          if (node.equals(assignment.getLeftHandSide())) {
            // field write access: xx= expression
            return assignment.getRightHandSide().resolveTypeBinding();
          }
          // read access
          return assignment.getLeftHandSide().resolveTypeBinding();
        case ASTNode.INFIX_EXPRESSION:
          InfixExpression infix = (InfixExpression) parent;
          InfixExpression.Operator op = infix.getOperator();
          if (op == InfixExpression.Operator.CONDITIONAL_AND
              || op == InfixExpression.Operator.CONDITIONAL_OR) {
            // boolean operation
            return infix.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
          } else if (op == InfixExpression.Operator.LEFT_SHIFT
              || op == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED
              || op == InfixExpression.Operator.RIGHT_SHIFT_SIGNED) {
            // asymmetric operation
            return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
          }
          if (node.equals(infix.getLeftOperand())) {
            //	xx operation expression
            ITypeBinding rigthHandBinding = infix.getRightOperand().resolveTypeBinding();
            if (rigthHandBinding != null) {
              return rigthHandBinding;
            }
          } else {
            // expression operation xx
            ITypeBinding leftHandBinding = infix.getLeftOperand().resolveTypeBinding();
            if (leftHandBinding != null) {
              return leftHandBinding;
            }
          }
          if (op != InfixExpression.Operator.EQUALS && op != InfixExpression.Operator.NOT_EQUALS) {
            return infix.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
          }
          break;
        case ASTNode.INSTANCEOF_EXPRESSION:
          InstanceofExpression instanceofExpression = (InstanceofExpression) parent;
          return instanceofExpression.getRightOperand().resolveBinding();
        case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
          VariableDeclarationFragment frag = (VariableDeclarationFragment) parent;
          if (frag.getInitializer().equals(node)) {
            return frag.getName().resolveTypeBinding();
          }
          break;
        case ASTNode.SUPER_METHOD_INVOCATION:
          SuperMethodInvocation superMethodInvocation = (SuperMethodInvocation) parent;
          IMethodBinding superMethodBinding =
              ASTNodes.getMethodBinding(superMethodInvocation.getName());
          if (superMethodBinding != null) {
            return getParameterTypeBinding(
                node, superMethodInvocation.arguments(), superMethodBinding);
          }
          break;
        case ASTNode.METHOD_INVOCATION:
          MethodInvocation methodInvocation = (MethodInvocation) parent;
          IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
          if (methodBinding != null) {
            return getParameterTypeBinding(node, methodInvocation.arguments(), methodBinding);
          }
          break;
        case ASTNode.SUPER_CONSTRUCTOR_INVOCATION:
          {
            SuperConstructorInvocation superInvocation = (SuperConstructorInvocation) parent;
            IMethodBinding superBinding = superInvocation.resolveConstructorBinding();
            if (superBinding != null) {
              return getParameterTypeBinding(node, superInvocation.arguments(), superBinding);
            }
            break;
          }
        case ASTNode.CONSTRUCTOR_INVOCATION:
          {
            ConstructorInvocation constrInvocation = (ConstructorInvocation) parent;
            IMethodBinding constrBinding = constrInvocation.resolveConstructorBinding();
            if (constrBinding != null) {
              return getParameterTypeBinding(node, constrInvocation.arguments(), constrBinding);
            }
            break;
          }
        case ASTNode.CLASS_INSTANCE_CREATION:
          {
            ClassInstanceCreation creation = (ClassInstanceCreation) parent;
            IMethodBinding creationBinding = creation.resolveConstructorBinding();
            if (creationBinding != null) {
              return getParameterTypeBinding(node, creation.arguments(), creationBinding);
            }
            break;
          }
        case ASTNode.PARENTHESIZED_EXPRESSION:
          return guessBindingForReference(parent);
        case ASTNode.ARRAY_ACCESS:
          if (((ArrayAccess) parent).getIndex().equals(node)) {
            return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
          } else {
            ITypeBinding parentBinding = getPossibleReferenceBinding(parent);
            if (parentBinding == null) {
              parentBinding = parent.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
            }
            return parentBinding.createArrayType(1);
          }
        case ASTNode.ARRAY_CREATION:
          if (((ArrayCreation) parent).dimensions().contains(node)) {
            return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
          }
          break;
        case ASTNode.ARRAY_INITIALIZER:
          ASTNode initializerParent = parent.getParent();
          int dim = 1;
          while (initializerParent instanceof ArrayInitializer) {
            initializerParent = initializerParent.getParent();
            dim++;
          }
          Type creationType = null;
          if (initializerParent instanceof ArrayCreation) {
            creationType = ((ArrayCreation) initializerParent).getType();
          } else if (initializerParent instanceof VariableDeclaration) {
            VariableDeclaration varDecl = (VariableDeclaration) initializerParent;
            creationType = ASTNodes.getType(varDecl);
            dim -= varDecl.getExtraDimensions();
          } else if (initializerParent instanceof MemberValuePair) {
            String name = ((MemberValuePair) initializerParent).getName().getIdentifier();
            IMethodBinding annotMember =
                findAnnotationMember((Annotation) initializerParent.getParent(), name);
            if (annotMember != null) {
              return getReducedDimensionBinding(annotMember.getReturnType(), dim);
            }
          }
          if (creationType instanceof ArrayType) {
            ITypeBinding creationTypeBinding = ((ArrayType) creationType).resolveBinding();
            if (creationTypeBinding != null) {
              return Bindings.getComponentType(creationTypeBinding, dim);
            }
          }
          break;
        case ASTNode.CONDITIONAL_EXPRESSION:
          ConditionalExpression expression = (ConditionalExpression) parent;
          if (node.equals(expression.getExpression())) {
            return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
          }
          if (node.equals(expression.getElseExpression())) {
            return expression.getThenExpression().resolveTypeBinding();
          }
          return expression.getElseExpression().resolveTypeBinding();
        case ASTNode.POSTFIX_EXPRESSION:
          return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
        case ASTNode.PREFIX_EXPRESSION:
          if (((PrefixExpression) parent).getOperator() == PrefixExpression.Operator.NOT) {
            return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
          }
          return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
        case ASTNode.IF_STATEMENT:
        case ASTNode.WHILE_STATEMENT:
        case ASTNode.DO_STATEMENT:
          if (node instanceof Expression) {
            return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
          }
          break;
        case ASTNode.SWITCH_STATEMENT:
          if (((SwitchStatement) parent).getExpression().equals(node)) {
            return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
          }
          break;
        case ASTNode.RETURN_STATEMENT:
          MethodDeclaration decl = ASTResolving.findParentMethodDeclaration(parent);
          if (decl != null && !decl.isConstructor()) {
            return decl.getReturnType2().resolveBinding();
          }
          LambdaExpression lambdaExpr = ASTResolving.findEnclosingLambdaExpression(parent);
          if (lambdaExpr != null) {
            IMethodBinding lambdaMethodBinding = lambdaExpr.resolveMethodBinding();
            if (lambdaMethodBinding != null && lambdaMethodBinding.getReturnType() != null) {
              return lambdaMethodBinding.getReturnType();
            }
          }
          break;
        case ASTNode.CAST_EXPRESSION:
          return ((CastExpression) parent).getType().resolveBinding();
        case ASTNode.THROW_STATEMENT:
        case ASTNode.CATCH_CLAUSE:
          return parent.getAST().resolveWellKnownType("java.lang.Exception"); //$NON-NLS-1$
        case ASTNode.FIELD_ACCESS:
          if (node.equals(((FieldAccess) parent).getName())) {
            return getPossibleReferenceBinding(parent);
          }
          break;
        case ASTNode.SUPER_FIELD_ACCESS:
          return getPossibleReferenceBinding(parent);
        case ASTNode.QUALIFIED_NAME:
          if (node.equals(((QualifiedName) parent).getName())) {
            return getPossibleReferenceBinding(parent);
          }
          break;
        case ASTNode.SWITCH_CASE:
          if (node.equals(((SwitchCase) parent).getExpression())
              && parent.getParent() instanceof SwitchStatement) {
            return ((SwitchStatement) parent.getParent()).getExpression().resolveTypeBinding();
          }
          break;
        case ASTNode.ASSERT_STATEMENT:
          if (node.getLocationInParent() == AssertStatement.EXPRESSION_PROPERTY) {
            return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
          }
          return parent.getAST().resolveWellKnownType("java.lang.String"); //$NON-NLS-1$
        case ASTNode.SINGLE_MEMBER_ANNOTATION:
          {
            IMethodBinding annotMember =
                findAnnotationMember((Annotation) parent, "value"); //$NON-NLS-1$
            if (annotMember != null) {
              return annotMember.getReturnType();
            }
            break;
          }
        case ASTNode.MEMBER_VALUE_PAIR:
          {
            String name = ((MemberValuePair) parent).getName().getIdentifier();
            IMethodBinding annotMember = findAnnotationMember((Annotation) parent.getParent(), name);
            if (annotMember != null) {
              return annotMember.getReturnType();
            }
            break;
          }
        default:
          // do nothing
      }
  
      return null;
    }
  
    private static IMethodBinding findAnnotationMember(Annotation annotation, String name) {
      ITypeBinding annotBinding = annotation.resolveTypeBinding();
      if (annotBinding != null) {
        return Bindings.findMethodInType(annotBinding, name, (String[]) null);
      }
      return null;
    }
  
    public static Type guessTypeForReference(AST ast, ASTNode node) {
      ASTNode parent = node.getParent();
      while (parent != null) {
        switch (parent.getNodeType()) {
          case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
            if (((VariableDeclarationFragment) parent).getInitializer() == node) {
              return ASTNodeFactory.newType(ast, (VariableDeclaration) parent);
            }
            return null;
          case ASTNode.SINGLE_VARIABLE_DECLARATION:
            if (((VariableDeclarationFragment) parent).getInitializer() == node) {
              return ASTNodeFactory.newType(ast, (VariableDeclaration) parent);
            }
            return null;
          case ASTNode.ARRAY_ACCESS:
            if (!((ArrayAccess) parent).getIndex().equals(node)) {
              Type type = guessTypeForReference(ast, parent);
              if (type != null) {
                return ASTNodeFactory.newArrayType(type);
              }
            }
            return null;
          case ASTNode.FIELD_ACCESS:
            if (node.equals(((FieldAccess) parent).getName())) {
              node = parent;
              parent = parent.getParent();
            } else {
              return null;
            }
            break;
          case ASTNode.SUPER_FIELD_ACCESS:
          case ASTNode.PARENTHESIZED_EXPRESSION:
            node = parent;
            parent = parent.getParent();
            break;
          case ASTNode.QUALIFIED_NAME:
            if (node.equals(((QualifiedName) parent).getName())) {
              node = parent;
              parent = parent.getParent();
            } else {
              return null;
            }
            break;
          default:
            return null;
        }
      }
      return null;
    }
  
    private static ITypeBinding getReducedDimensionBinding(
        ITypeBinding arrayBinding, int dimsToReduce) {
      while (dimsToReduce > 0) {
        arrayBinding = arrayBinding.getComponentType();
        dimsToReduce--;
      }
      return arrayBinding;
    }
  
    private static ITypeBinding getParameterTypeBinding(
        ASTNode node, List<Expression> args, IMethodBinding binding) {
      int index = args.indexOf(node);
      return getParameterTypeBinding(binding, index);
    }
  
    public static ITypeBinding getParameterTypeBinding(
        IMethodBinding methodBinding, int argumentIndex) {
      ITypeBinding[] paramTypes = methodBinding.getParameterTypes();
      if (methodBinding.isVarargs() && argumentIndex >= paramTypes.length - 1) {
        return paramTypes[paramTypes.length - 1].getComponentType();
      }
      if (argumentIndex >= 0 && argumentIndex < paramTypes.length) {
        return paramTypes[argumentIndex];
      }
      return null;
    }
  
    public static ITypeBinding guessBindingForTypeReference(ASTNode node) {
      StructuralPropertyDescriptor locationInParent = node.getLocationInParent();
      if (locationInParent == QualifiedName.QUALIFIER_PROPERTY) {
        return null; // can't guess type for X.A
      }
      if (locationInParent == SimpleType.NAME_PROPERTY
          || locationInParent == NameQualifiedType.NAME_PROPERTY) {
        node = node.getParent();
      }
      ITypeBinding binding = Bindings.normalizeTypeBinding(getPossibleTypeBinding(node));
      if (binding != null) {
        if (binding.isWildcardType()) {
          return normalizeWildcardType(binding, true, node.getAST());
        }
      }
      return binding;
    }
  
    private static ITypeBinding getPossibleTypeBinding(ASTNode node) {
      ASTNode parent = node.getParent();
      switch (parent.getNodeType()) {
        case ASTNode.ARRAY_TYPE:
          {
            int dim = ((ArrayType) parent).getDimensions();
            ITypeBinding parentBinding = getPossibleTypeBinding(parent);
            if (parentBinding != null && parentBinding.getDimensions() == dim) {
              return parentBinding.getElementType();
            }
            return null;
          }
        case ASTNode.PARAMETERIZED_TYPE:
          {
            ITypeBinding parentBinding = getPossibleTypeBinding(parent);
            if (parentBinding == null || !parentBinding.isParameterizedType()) {
              return null;
            }
            if (node.getLocationInParent() == ParameterizedType.TYPE_PROPERTY) {
              return parentBinding;
            }
  
            ITypeBinding[] typeArguments = parentBinding.getTypeArguments();
            List<Type> argumentNodes = ((ParameterizedType) parent).typeArguments();
            int index = argumentNodes.indexOf(node);
            if (index != -1 && typeArguments.length == argumentNodes.size()) {
              return typeArguments[index];
            }
            return null;
          }
        case ASTNode.WILDCARD_TYPE:
          {
            ITypeBinding parentBinding = getPossibleTypeBinding(parent);
            if (parentBinding == null || !parentBinding.isWildcardType()) {
              return null;
            }
            WildcardType wildcardType = (WildcardType) parent;
            if (parentBinding.isUpperbound() == wildcardType.isUpperBound()) {
              return parentBinding.getBound();
            }
            return null;
          }
        case ASTNode.QUALIFIED_TYPE:
          {
            ITypeBinding parentBinding = getPossibleTypeBinding(parent);
            if (parentBinding == null || !parentBinding.isMember()) {
              return null;
            }
            if (node.getLocationInParent() == QualifiedType.QUALIFIER_PROPERTY) {
              return parentBinding.getDeclaringClass();
            }
            return parentBinding;
          }
        case ASTNode.NAME_QUALIFIED_TYPE:
          {
            ITypeBinding parentBinding = getPossibleTypeBinding(parent);
            if (parentBinding == null || !parentBinding.isMember()) {
              return null;
            }
            if (node.getLocationInParent() == NameQualifiedType.QUALIFIER_PROPERTY) {
              return parentBinding.getDeclaringClass();
            }
            return parentBinding;
          }
        case ASTNode.VARIABLE_DECLARATION_STATEMENT:
          return guessVariableType(((VariableDeclarationStatement) parent).fragments());
        case ASTNode.FIELD_DECLARATION:
          return guessVariableType(((FieldDeclaration) parent).fragments());
        case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
          return guessVariableType(((VariableDeclarationExpression) parent).fragments());
        case ASTNode.SINGLE_VARIABLE_DECLARATION:
          SingleVariableDeclaration varDecl = (SingleVariableDeclaration) parent;
          if (varDecl.getInitializer() != null) {
            return Bindings.normalizeTypeBinding(varDecl.getInitializer().resolveTypeBinding());
          }
          break;
        case ASTNode.ARRAY_CREATION:
          ArrayCreation creation = (ArrayCreation) parent;
          if (creation.getInitializer() != null) {
            return creation.getInitializer().resolveTypeBinding();
          }
          return getPossibleReferenceBinding(parent);
        case ASTNode.TYPE_LITERAL:
          return ((TypeLiteral) parent).getType().resolveBinding();
        case ASTNode.CLASS_INSTANCE_CREATION:
          return getPossibleReferenceBinding(parent);
        case ASTNode.CAST_EXPRESSION:
          return getPossibleReferenceBinding(parent);
        case ASTNode.TAG_ELEMENT:
          TagElement tagElement = (TagElement) parent;
          if (TagElement.TAG_THROWS.equals(tagElement.getTagName())
              || TagElement.TAG_EXCEPTION.equals(tagElement.getTagName())) {
            ASTNode methNode = tagElement.getParent().getParent();
            if (methNode instanceof MethodDeclaration) {
              List<Type> thrownExceptions = ((MethodDeclaration) methNode).thrownExceptionTypes();
  