Package org.eclipse.jdt.internal.codeassist

Source Code of org.eclipse.jdt.internal.codeassist.ThrownExceptionFinder

/*******************************************************************************
* Copyright (c) 2007, 2013 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
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.codeassist;

import java.util.Stack;

import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.Block;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
import org.eclipse.jdt.internal.compiler.ast.TryStatement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;

@SuppressWarnings({"rawtypes", "unchecked"})
public class ThrownExceptionFinder extends ASTVisitor {

  private SimpleSet thrownExceptions;
  private Stack exceptionsStack;
  private SimpleSet caughtExceptions;
  private SimpleSet discouragedExceptions;

  /**
   * Finds the thrown exceptions minus the ones that are already caught in previous catch blocks.
   * Exception is already caught even if its super type is being caught. Also computes, separately,
   * a list comprising of (a)those exceptions that have been caught already and (b)those exceptions that are thrown
   * by the method and whose super type has been caught already.
   * @param tryStatement
   * @param scope
   */
  public void processThrownExceptions(TryStatement tryStatement, BlockScope scope) {
    this.thrownExceptions = new SimpleSet();
    this.exceptionsStack = new Stack();
    this.caughtExceptions = new SimpleSet();
    this.discouragedExceptions = new SimpleSet();
    tryStatement.traverse(this, scope);
    removeCaughtExceptions(tryStatement, true /*remove unchecked exceptions this time*/);
  }

  private void acceptException(ReferenceBinding binding) {
    if (binding != null && binding.isValidBinding()) {
      this.thrownExceptions.add(binding);
    }
  }

  public void endVisit(MessageSend messageSend, BlockScope scope) {
    if (messageSend.binding != null) {
      endVisitMethodInvocation(messageSend.binding);
    }
    super.endVisit(messageSend, scope);
  }

  public void endVisit(AllocationExpression allocationExpression, BlockScope scope) {
    if (allocationExpression.binding != null) {
      endVisitMethodInvocation(allocationExpression.binding);
    }
    super.endVisit(allocationExpression, scope);
  }

  public void endVisit(ThrowStatement throwStatement, BlockScope scope) {
    acceptException((ReferenceBinding)throwStatement.exception.resolvedType);
    super.endVisit(throwStatement, scope);
  }


  private void endVisitMethodInvocation(MethodBinding methodBinding) {
    ReferenceBinding[] thrownExceptionBindings = methodBinding.thrownExceptions;
    int length = thrownExceptionBindings == null ? 0 : thrownExceptionBindings.length;
    for (int i = 0; i < length; i++) {
      acceptException(thrownExceptionBindings[i]);
    }
  }


  /**
   * Returns all the already caught exceptions in catch blocks, found by the call to
   * {@link ThrownExceptionFinder#processThrownExceptions(TryStatement, BlockScope)}
   * @return Returns an array of those exceptions that have been caught already in previous catch or
   * multi-catch blocks of the same try block. (Exceptions caught in inner try-catches are obtained via
   * {@link ThrownExceptionFinder#getDiscouragedExceptions()}.
   */
  public ReferenceBinding[] getAlreadyCaughtExceptions() {
    ReferenceBinding[] allCaughtExceptions = new ReferenceBinding[this.caughtExceptions.elementSize];
    this.caughtExceptions.asArray(allCaughtExceptions);
    return allCaughtExceptions;
  }
 
  /**
   * Returns all the thrown exceptions minus the ones that are already caught in previous catch blocks
   * (of the same try), found by the call to
   * {@link ThrownExceptionFinder#processThrownExceptions(TryStatement, BlockScope)}.
   * @return Returns an array of thrown exceptions that are still not caught in any catch block.
   */
  public ReferenceBinding[] getThrownUncaughtExceptions() {
    ReferenceBinding[] result = new ReferenceBinding[this.thrownExceptions.elementSize];
    this.thrownExceptions.asArray(result);
    return result;
  }
 
  /**
   * Returns all exceptions that are discouraged to use because (a) they are already caught in some inner try-catch,
   * or (b) their super exception has already been caught.
   * @return all discouraged exceptions
   */
  public ReferenceBinding[] getDiscouragedExceptions() {
    ReferenceBinding[] allDiscouragedExceptions = new ReferenceBinding[this.discouragedExceptions.elementSize];
    this.discouragedExceptions.asArray(allDiscouragedExceptions);
    return allDiscouragedExceptions;
  }
  public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
    return visitType(typeDeclaration);
  }

  public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
    return visitType(memberTypeDeclaration);
  }

  public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
    return visitType(localTypeDeclaration);
  }

  private boolean visitType(TypeDeclaration typeDeclaration) {
    return false;
  }

  public boolean visit(TryStatement tryStatement, BlockScope scope) {
    this.exceptionsStack.push(this.thrownExceptions);
    SimpleSet exceptionSet = new SimpleSet();
    this.thrownExceptions = exceptionSet;
    tryStatement.tryBlock.traverse(this, scope);

    removeCaughtExceptions(tryStatement, false);

    this.thrownExceptions = (SimpleSet)this.exceptionsStack.pop();

    Object[] values = exceptionSet.values;
    for (int i = 0; i < values.length; i++) {
      if (values[i] != null) {
        this.thrownExceptions.add(values[i]);
      }
    }

    Block[] catchBlocks = tryStatement.catchBlocks;
    int length = catchBlocks == null ? 0 : catchBlocks.length;
    for (int i = 0; i < length; i++) {
      catchBlocks[i].traverse(this, scope);
    }
    return false;
  }
 
  private void removeCaughtExceptions(TryStatement tryStatement, boolean recordUncheckedCaughtExceptions) {
    Argument[] catchArguments = tryStatement.catchArguments;
    int length = catchArguments == null ? 0 : catchArguments.length;
    for (int i = 0; i < length; i++) {
      if (catchArguments[i].type instanceof UnionTypeReference) {
        UnionTypeReference unionTypeReference = (UnionTypeReference) catchArguments[i].type;
        TypeBinding caughtException;
        for (int j = 0; j < unionTypeReference.typeReferences.length; j++) {
          caughtException = unionTypeReference.typeReferences[j].resolvedType;
          if ((caughtException instanceof ReferenceBinding) && caughtException.isValidBinding()) {  // might be null when its the completion node
            if (recordUncheckedCaughtExceptions) {
              // is in outermost try-catch. Remove all caught exceptions, unchecked or checked
              removeCaughtException((ReferenceBinding)caughtException);
              this.caughtExceptions.add(caughtException);
            } else {
              // is in some inner try-catch. Discourage already caught checked exceptions
              // from being proposed in an outer catch.
              if (!caughtException.isUncheckedException(true)) {
                this.discouragedExceptions.add(caughtException);
              }
            }
          }
        }
      } else {
        TypeBinding exception = catchArguments[i].type.resolvedType;
        if ((exception instanceof ReferenceBinding) && exception.isValidBinding()) {
          if (recordUncheckedCaughtExceptions) {
            // is in outermost try-catch. Remove all caught exceptions, unchecked or checked
            removeCaughtException((ReferenceBinding)exception);
            this.caughtExceptions.add(exception);
          } else {
            // is in some inner try-catch. Discourage already caught checked exceptions
            // from being proposed in an outer catch
            if (!exception.isUncheckedException(true)) {
              this.discouragedExceptions.add(exception);
            }
          }
        }
      }
    }
  }

  private void removeCaughtException(ReferenceBinding caughtException) {
    Object[] exceptions = this.thrownExceptions.values;
    for (int i = 0; i < exceptions.length; i++) {
      ReferenceBinding exception = (ReferenceBinding)exceptions[i];
      if (exception != null) {
        if (TypeBinding.equalsEquals(exception, caughtException)) {
          this.thrownExceptions.remove(exception);
        } else if (caughtException.isSuperclassOf(exception)) {
          // catching the sub-exception when super has been caught already will give an error
          // so remove it from thrown list and lower the relevance for cases when it is found
          // from searchAllTypes(..)
          this.thrownExceptions.remove(exception);
          this.discouragedExceptions.add(exception);
        }
      }
    }
  }
}
TOP

Related Classes of org.eclipse.jdt.internal.codeassist.ThrownExceptionFinder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.