mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
Project Coin precise rethrow support
This commit is contained in:
@@ -22,7 +22,10 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -67,7 +70,7 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiClassType> getThrownExceptions(@NotNull PsiElement element) {
|
||||
public static List<PsiClassType> getThrownExceptions(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiClass) {
|
||||
if (element instanceof PsiAnonymousClass) {
|
||||
final PsiExpressionList argumentList = ((PsiAnonymousClass)element).getArgumentList();
|
||||
@@ -88,15 +91,14 @@ public class ExceptionUtil {
|
||||
return getExceptionsByMethodAndChildren(element, result);
|
||||
}
|
||||
else if (element instanceof PsiThrowStatement) {
|
||||
PsiExpression expr = ((PsiThrowStatement)element).getException();
|
||||
final PsiExpression expr = ((PsiThrowStatement)element).getException();
|
||||
if (expr == null) return Collections.emptyList();
|
||||
PsiType exception = expr.getType();
|
||||
List<PsiClassType> array = new ArrayList<PsiClassType>();
|
||||
if (exception instanceof PsiClassType) {
|
||||
array.add((PsiClassType)exception);
|
||||
}
|
||||
addExceptions(array, getThrownExceptions(expr));
|
||||
return array;
|
||||
final List<PsiType> types = getPreciseThrowTypes(expr);
|
||||
final List<PsiClassType> classTypes = ContainerUtil.mapNotNull(types, new NullableFunction<PsiType, PsiClassType>() {
|
||||
@Override public PsiClassType fun(PsiType type) { return type instanceof PsiClassType ? (PsiClassType)type : null; }
|
||||
});
|
||||
addExceptions(classTypes, getThrownExceptions(expr));
|
||||
return classTypes;
|
||||
}
|
||||
else if (element instanceof PsiTryStatement) {
|
||||
PsiTryStatement tryStatement = (PsiTryStatement)element;
|
||||
@@ -203,8 +205,7 @@ public class ExceptionUtil {
|
||||
}
|
||||
else if (element instanceof PsiThrowStatement) {
|
||||
PsiThrowStatement statement = (PsiThrowStatement)element;
|
||||
PsiClassType exception = getUnhandledException(statement, topElement);
|
||||
unhandledExceptions = exception == null ? Collections.<PsiClassType>emptyList() : Collections.singletonList(exception);
|
||||
unhandledExceptions = getUnhandledExceptions(statement, topElement);
|
||||
}
|
||||
else if (element instanceof PsiCodeBlock &&
|
||||
element.getParent() instanceof PsiMethod &&
|
||||
@@ -293,7 +294,7 @@ public class ExceptionUtil {
|
||||
|
||||
@Override
|
||||
public void visitThrowStatement(PsiThrowStatement statement) {
|
||||
addException(array, getUnhandledException(statement, null));
|
||||
addExceptions(array, getUnhandledExceptions(statement, null));
|
||||
visitElement(statement);
|
||||
}
|
||||
|
||||
@@ -319,14 +320,13 @@ public class ExceptionUtil {
|
||||
}
|
||||
else if (element instanceof PsiThrowStatement) {
|
||||
PsiThrowStatement throwStatement = (PsiThrowStatement)element;
|
||||
PsiClassType exception = getUnhandledException(throwStatement, null);
|
||||
if (exception != null) return Collections.singletonList(exception);
|
||||
return getUnhandledExceptions(throwStatement, null);
|
||||
}
|
||||
else if (element instanceof PsiResourceVariable) {
|
||||
return getUnhandledCloserExceptions((PsiResourceVariable)element, null);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
return getUnhandledExceptions(new PsiElement[]{element});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -358,19 +358,41 @@ public class ExceptionUtil {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClassType getUnhandledException(PsiThrowStatement throwStatement, PsiElement topElement) {
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledExceptions(final PsiThrowStatement throwStatement, final PsiElement topElement) {
|
||||
final PsiExpression exception = throwStatement.getException();
|
||||
if (exception != null) {
|
||||
final PsiType type = exception.getType();
|
||||
if (type instanceof PsiClassType) {
|
||||
PsiClassType classType = (PsiClassType)type;
|
||||
if (!isUncheckedException(classType) && !isHandled(throwStatement, classType, topElement)) {
|
||||
return classType;
|
||||
final List<PsiType> types = getPreciseThrowTypes(exception);
|
||||
return ContainerUtil.mapNotNull(types, new NullableFunction<PsiType, PsiClassType>() {
|
||||
@Override
|
||||
public PsiClassType fun(PsiType type) {
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClassType classType = (PsiClassType)type;
|
||||
if (!isUncheckedException(classType) && !isHandled(throwStatement, classType, topElement)) {
|
||||
return classType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiType> getPreciseThrowTypes(@Nullable final PsiExpression expression) {
|
||||
if (expression instanceof PsiReferenceExpression) {
|
||||
final PsiElement target = ((PsiReferenceExpression)expression).resolve();
|
||||
if (target != null && PsiUtil.isCatchParameter(target)) {
|
||||
return ((PsiCatchSection)target.getParent()).getPreciseCatchTypes();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
if (expression != null) {
|
||||
final PsiType type = expression.getType();
|
||||
if (type != null) {
|
||||
return Arrays.asList(type);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -433,11 +455,11 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
final PsiClass errorClass = ApplicationManager.getApplication().runReadAction(
|
||||
new NullableComputable<PsiClass>() {
|
||||
public PsiClass compute() {
|
||||
return JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.lang.Error", searchScope);
|
||||
}
|
||||
new NullableComputable<PsiClass>() {
|
||||
public PsiClass compute() {
|
||||
return JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.lang.Error", searchScope);
|
||||
}
|
||||
}
|
||||
);
|
||||
return errorClass != null && InheritanceUtil.isInheritorOrSelf(aClass, errorClass, true);
|
||||
}
|
||||
@@ -526,14 +548,9 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
private static boolean isCaught(PsiTryStatement tryStatement, PsiClassType exceptionType) {
|
||||
// if finally block completes abruptly, exception gets lost
|
||||
PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
|
||||
if (finallyBlock != null) {
|
||||
List<PsiClassType> exceptions = getUnhandledExceptions(finallyBlock);
|
||||
if (exceptions.contains(exceptionType)) return false;
|
||||
// if finally block completes normally, exception not caught
|
||||
// if finally block completes abruptly, exception gets lost
|
||||
if (blockCompletesAbruptly(finallyBlock)) return true;
|
||||
}
|
||||
if (finallyBlock != null && blockCompletesAbruptly(finallyBlock)) return true;
|
||||
|
||||
final PsiParameter[] catchBlockParameters = tryStatement.getCatchBlockParameters();
|
||||
for (PsiParameter parameter : catchBlockParameters) {
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ public class AddExceptionToThrowsFix extends BaseIntentionAction {
|
||||
|
||||
@Nullable
|
||||
private static PsiElement findElement(PsiElement element, PsiMethod topElement) {
|
||||
if (element == null) return null;
|
||||
if (element == null || element == topElement) return null;
|
||||
List<PsiClassType> unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element);
|
||||
if (!filterInProjectExceptions(topElement, unhandledExceptions).isEmpty()) {
|
||||
return element;
|
||||
|
||||
+22
-16
@@ -68,29 +68,34 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
|
||||
private void addExceptionThrownPlaces(final PsiType type) {
|
||||
if (type instanceof PsiClassType) {
|
||||
myPlace.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
visitElement(expression);
|
||||
}
|
||||
|
||||
@Override public void visitThrowStatement(PsiThrowStatement statement) {
|
||||
@Override
|
||||
public void visitThrowStatement(PsiThrowStatement statement) {
|
||||
super.visitThrowStatement(statement);
|
||||
PsiClassType actualType = ExceptionUtil.getUnhandledException(statement, myPlace);
|
||||
if (actualType != null && type.isAssignableFrom(actualType) && myTypeFilter.value(actualType)) {
|
||||
PsiExpression psiExpression = statement.getException();
|
||||
if (psiExpression instanceof PsiReferenceExpression) {
|
||||
addOccurrence(psiExpression);
|
||||
}
|
||||
else if (psiExpression instanceof PsiNewExpression) {
|
||||
PsiJavaCodeReferenceElement ref = ((PsiNewExpression)psiExpression).getClassReference();
|
||||
addOccurrence(ref);
|
||||
}
|
||||
else {
|
||||
addOccurrence(statement.getException());
|
||||
final List<PsiClassType> actualTypes = ExceptionUtil.getUnhandledExceptions(statement, myPlace);
|
||||
for (PsiClassType actualType : actualTypes) {
|
||||
if (actualType != null && type.isAssignableFrom(actualType) && myTypeFilter.value(actualType)) {
|
||||
PsiExpression psiExpression = statement.getException();
|
||||
if (psiExpression instanceof PsiReferenceExpression) {
|
||||
addOccurrence(psiExpression);
|
||||
}
|
||||
else if (psiExpression instanceof PsiNewExpression) {
|
||||
PsiJavaCodeReferenceElement ref = ((PsiNewExpression)psiExpression).getClassReference();
|
||||
addOccurrence(ref);
|
||||
}
|
||||
else {
|
||||
addOccurrence(statement.getException());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
PsiReference reference = expression.getMethodExpression().getReference();
|
||||
if (reference == null) return;
|
||||
@@ -103,7 +108,8 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitNewExpression(PsiNewExpression expression) {
|
||||
@Override
|
||||
public void visitNewExpression(PsiNewExpression expression) {
|
||||
super.visitNewExpression(expression);
|
||||
PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
|
||||
if (classReference == null) return;
|
||||
|
||||
@@ -15,25 +15,36 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.tree.java;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
import com.intellij.psi.impl.source.tree.ChildRole;
|
||||
import com.intellij.psi.impl.source.tree.CompositePsiElement;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.ChildRoleBase;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class PsiCatchSectionImpl extends CompositePsiElement implements PsiCatchSection, Constants {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiCatchSectionImpl");
|
||||
|
||||
private CachedValue<List<PsiType>> myTypesCache = null;
|
||||
|
||||
public PsiCatchSectionImpl() {
|
||||
super(CATCH_SECTION);
|
||||
}
|
||||
@@ -52,6 +63,85 @@ public class PsiCatchSectionImpl extends CompositePsiElement implements PsiCatch
|
||||
return parameter.getType();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PsiType> getPreciseCatchTypes() {
|
||||
final PsiParameter parameter = getParameter();
|
||||
if (parameter == null) return Collections.emptyList();
|
||||
|
||||
return getTypesCache().getValue();
|
||||
}
|
||||
|
||||
private synchronized CachedValue<List<PsiType>> getTypesCache() {
|
||||
if (myTypesCache == null) {
|
||||
final CachedValuesManager cacheManager = CachedValuesManager.getManager(getProject());
|
||||
myTypesCache = cacheManager.createCachedValue(new CachedValueProvider<List<PsiType>>() {
|
||||
@Override public Result<List<PsiType>> compute() {
|
||||
final List<PsiType> types = computePreciseCatchTypes(getParameter());
|
||||
return Result.create(types, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
return myTypesCache;
|
||||
}
|
||||
|
||||
private List<PsiType> computePreciseCatchTypes(final PsiParameter parameter) {
|
||||
final PsiType declaredType = parameter.getType();
|
||||
|
||||
// When the thrown expression is a ... exception parameter Ej (parameter) of a catch clause Cj (this) ...
|
||||
final LanguageLevel level = PsiUtil.getLanguageLevel(parameter);
|
||||
if (level.isAtLeast(LanguageLevel.JDK_1_7)) {
|
||||
if (isCatchParameterEffectivelyFinal(parameter, getCatchBlock())) {
|
||||
final PsiCodeBlock tryBlock = getTryStatement().getTryBlock();
|
||||
if (tryBlock != null) {
|
||||
// ... and the try block of the try statement which declares Cj (tryBlock) can throw T ...
|
||||
final List<PsiClassType> thrownTypes = ExceptionUtil.getThrownExceptions(tryBlock);
|
||||
// ... and for all exception parameters Ei declared by any catch clauses Ci, 1 <= i < j,
|
||||
// declared to the left of Cj for the same try statement, T is not assignable to Ei ...
|
||||
final PsiParameter[] parameters = getTryStatement().getCatchBlockParameters();
|
||||
final List<PsiType> uncaughtTypes = ContainerUtil.mapNotNull(thrownTypes, new NullableFunction<PsiClassType, PsiType>() {
|
||||
@Override public PsiType fun(final PsiClassType thrownType) {
|
||||
for (int i = 0; i < parameters.length && parameters[i] != parameter && thrownTypes.size() > 0; i++) {
|
||||
final PsiType catchType = parameters[i].getType();
|
||||
if (catchType.isAssignableFrom(thrownType)) return null;
|
||||
}
|
||||
return thrownType;
|
||||
}
|
||||
});
|
||||
// ... and T is assignable to Ej ...
|
||||
boolean passed = true;
|
||||
for (PsiType type : uncaughtTypes) {
|
||||
if (!declaredType.isAssignableFrom(type)) {
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// ... the throw statement throws precisely the set of exception types T.
|
||||
if (passed) return uncaughtTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.asList(declaredType);
|
||||
}
|
||||
|
||||
// do not use control flow here to avoid dead loop
|
||||
private static boolean isCatchParameterEffectivelyFinal(final PsiParameter parameter, final PsiCodeBlock catchBlock) {
|
||||
final boolean[] result = {true};
|
||||
if (catchBlock != null) {
|
||||
catchBlock.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitAssignmentExpression(final PsiAssignmentExpression expression) {
|
||||
final PsiExpression left = expression.getLExpression();
|
||||
if (left instanceof PsiReferenceExpression && parameter.equals(((PsiReferenceExpression)left).resolve())) {
|
||||
result[0] = false;
|
||||
stopWalking();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiTryStatement getTryStatement() {
|
||||
return (PsiTryStatement)getParent();
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
import java.lang.Exception;
|
||||
|
||||
class C {
|
||||
static class E extends Exception { }
|
||||
static class E1 extends E { }
|
||||
static class E2 extends E { }
|
||||
|
||||
void m1() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
// throws Exception before JDK7
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
catch (E2 e2) { }
|
||||
}
|
||||
}
|
||||
|
||||
void m2() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
e = new E1(); // no effect before JDK7
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
catch (E2 e2) { }
|
||||
}
|
||||
}
|
||||
|
||||
void m3(boolean f) throws E1, E2 {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else
|
||||
throw new E2();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// throws Exception before JDK7
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
}
|
||||
|
||||
void m4(boolean f) throws E1, E2 {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else
|
||||
throw new E2();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e = new E2(); // no effect before JDK7
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
}
|
||||
|
||||
void m5(boolean f) throws E {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else if (!f)
|
||||
throw new E2();
|
||||
else
|
||||
throw (Throwable)new E();
|
||||
}
|
||||
catch (E1 e1) { }
|
||||
catch (final Exception e) {
|
||||
// throws Exception
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
catch (Throwable t) { }
|
||||
}
|
||||
|
||||
void m6(boolean f) throws E2 {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else if (!f)
|
||||
throw new E2();
|
||||
}
|
||||
catch (E1 e1) { }
|
||||
catch (final Exception e) {
|
||||
// throws Exception before JDK7
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
}
|
||||
|
||||
void m7() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (E e) {
|
||||
try {
|
||||
throw e;
|
||||
}
|
||||
catch (E x) {
|
||||
// no chained exception type evaluation
|
||||
<error descr="Unhandled exception: C.E">throw x;</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void m8() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (E e) {
|
||||
E x = e;
|
||||
// no chained exception type evaluation
|
||||
<error descr="Unhandled exception: C.E">throw x;</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
class C {
|
||||
static class E extends Exception { }
|
||||
static class E1 extends E { }
|
||||
static class E2 extends E { }
|
||||
|
||||
void m0() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
// throws E1 in JDK7
|
||||
<error descr="Unhandled exception: C.E1">throw e;</error>
|
||||
} catch (E2 e2) { }
|
||||
}
|
||||
}
|
||||
|
||||
void m1() throws E1 {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
// throws E1 in JDK7
|
||||
throw e;
|
||||
} catch (<error descr="Exception 'C.E2' is never thrown in the corresponding try block">E2 e2</error>) { }
|
||||
}
|
||||
}
|
||||
|
||||
void m2() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
if (true) {
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
e = new E1(); // analysis disabled, even by late assignment
|
||||
}
|
||||
catch (E2 e2) { }
|
||||
}
|
||||
}
|
||||
|
||||
void m3(boolean f) throws E1, E2 {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else
|
||||
throw new E2();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// read access doesn't disables an analysis
|
||||
System.out.println(e);
|
||||
// throws E1, E2 in JDK7
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
void m4(boolean f) throws E1, E2 {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else
|
||||
throw new E2();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e = new E2(); // analysis disabled
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
}
|
||||
|
||||
void m5(boolean f) throws E {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else if (!f)
|
||||
throw new E2();
|
||||
else
|
||||
throw (Throwable)new E();
|
||||
}
|
||||
catch (E1 e1) { }
|
||||
catch (final Exception e) {
|
||||
// Throwable isn't a subtype of Exception
|
||||
<error descr="Unhandled exception: java.lang.Exception">throw e;</error>
|
||||
}
|
||||
catch (Throwable t) { }
|
||||
}
|
||||
|
||||
void m6(boolean f) throws E2 {
|
||||
try {
|
||||
if (f)
|
||||
throw new E1();
|
||||
else if (!f)
|
||||
throw new E2();
|
||||
}
|
||||
catch (E1 e1) { }
|
||||
catch (final Exception e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
void m7() {
|
||||
try {
|
||||
if (true)
|
||||
throw new E1();
|
||||
else if (false)
|
||||
throw new E2();
|
||||
}
|
||||
catch (E e) {
|
||||
// throws E1, E2 in JDK7
|
||||
<error descr="Unhandled exceptions: C.E1, C.E2">throw e;</error>
|
||||
}
|
||||
}
|
||||
|
||||
void m8() throws E1 {
|
||||
try {
|
||||
if (true)
|
||||
throw new E1();
|
||||
else if (false)
|
||||
throw new E2();
|
||||
}
|
||||
catch (E1 | E2 e) {
|
||||
<error descr="Unhandled exception: C.E2">throw e;</error>
|
||||
}
|
||||
}
|
||||
|
||||
void m9() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (E x) {
|
||||
try {
|
||||
throw x;
|
||||
}
|
||||
catch (E y) {
|
||||
try {
|
||||
throw y;
|
||||
}
|
||||
catch (E z) {
|
||||
// chained exception type evaluation
|
||||
<error descr="Unhandled exception: C.E1">throw z;</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void m10() {
|
||||
try {
|
||||
throw new E1();
|
||||
}
|
||||
catch (E e) {
|
||||
E x = e;
|
||||
// no chained exception type evaluation
|
||||
<error descr="Unhandled exception: C.E">throw x;</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -107,8 +107,6 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
|
||||
doTest(false, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testDiamondMisc() throws Exception {
|
||||
doTest(false, false);
|
||||
}
|
||||
@@ -205,4 +203,8 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testUncheckedGenericsArrayCreation() throws Exception {
|
||||
doTest(true, false);
|
||||
}
|
||||
|
||||
public void testPreciseRethrow() throws Exception {
|
||||
doTest(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,4 +311,8 @@ public class LightAdvHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
configureFromFileText("a.java", "class A extends B { String s = \"\"; void f() {}} class B extends A { void f() {} } ");
|
||||
doHighlighting();
|
||||
}
|
||||
|
||||
public void testClassicRethrow() throws Exception {
|
||||
doTest(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.intellij.psi;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a single <code>catch</code> section of a Java <code>try ... catch</code> statement.
|
||||
*
|
||||
@@ -53,6 +55,16 @@ public interface PsiCatchSection extends PsiElement {
|
||||
@Nullable
|
||||
PsiType getCatchType();
|
||||
|
||||
/**
|
||||
* For language level 7 or higher returns the list of possible types for its parameter re-throw
|
||||
* (as defined in Project Coin/JSR 334 section "Multi-catch and more precise rethrow").
|
||||
* Otherwise, returns parameter's declared type.
|
||||
*
|
||||
* @return the types, or empty list if the section is incomplete.
|
||||
*/
|
||||
@NotNull
|
||||
List<PsiType> getPreciseCatchTypes();
|
||||
|
||||
/**
|
||||
* Returns the <code>try</code> statement to which the catch section is attached.
|
||||
*
|
||||
|
||||
@@ -891,12 +891,14 @@ public final class PsiUtil extends PsiUtilBase {
|
||||
modifierList.setModifierProperty(property, value);
|
||||
}
|
||||
|
||||
public static boolean isTryBlock(final PsiElement element) {
|
||||
public static boolean isTryBlock(@Nullable final PsiElement element) {
|
||||
if (element == null) return false;
|
||||
final PsiElement parent = element.getParent();
|
||||
return parent instanceof PsiTryStatement && element == ((PsiTryStatement)parent).getTryBlock();
|
||||
}
|
||||
|
||||
public static boolean isElseBlock(final PsiElement element) {
|
||||
public static boolean isElseBlock(@Nullable final PsiElement element) {
|
||||
if (element == null) return false;
|
||||
final PsiElement parent = element.getParent();
|
||||
return parent instanceof PsiIfStatement && element == ((PsiIfStatement)parent).getElseBranch();
|
||||
}
|
||||
@@ -904,4 +906,8 @@ public final class PsiUtil extends PsiUtilBase {
|
||||
public static boolean isJavaToken(@Nullable final PsiElement element, final IElementType type) {
|
||||
return element instanceof PsiJavaToken && ((PsiJavaToken)element).getTokenType() == type;
|
||||
}
|
||||
|
||||
public static boolean isCatchParameter(@Nullable final PsiElement element) {
|
||||
return element instanceof PsiParameter && element.getParent() instanceof PsiCatchSection;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user