[java] exception highlighting in try-with-resources (IDEA-142066)

This commit is contained in:
Roman Shevchenko
2016-02-29 18:32:21 +01:00
parent 1cef8eae98
commit 7cb95f22b5
3 changed files with 76 additions and 13 deletions
@@ -29,7 +29,7 @@ import java.util.List;
public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiClass> {
private final PsiElement myTarget;
private final PsiClassType[] myClassTypes;
private final PsiElement myPlace;
private final PsiElement myPlace, myOtherPlace;
private final Condition<PsiType> myTypeFilter;
public HighlightExceptionsHandler(Editor editor,
@@ -37,11 +37,13 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
PsiElement target,
PsiClassType[] classTypes,
PsiElement place,
PsiElement otherPlace,
Condition<PsiType> typeFilter) {
super(editor, file);
myTarget = target;
myClassTypes = classTypes;
myPlace = place;
myOtherPlace = otherPlace;
myTypeFilter = typeFilter;
}
@@ -66,14 +68,17 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
PsiElementFactory factory = JavaPsiFacade.getInstance(myEditor.getProject()).getElementFactory();
for (PsiClass aClass : targets) {
addExceptionThrownPlaces(factory.createType(aClass));
addExceptionThrowPlaces(factory.createType(aClass), myPlace);
if (myOtherPlace != null) {
addExceptionThrowPlaces(factory.createType(aClass), myOtherPlace);
}
}
buildStatusText(LangBundle.message("java.terms.exception"), myReadUsages.size() - 1 /* exclude target */);
}
private void addExceptionThrownPlaces(PsiClassType type) {
myPlace.accept(new JavaRecursiveElementWalkingVisitor() {
private void addExceptionThrowPlaces(PsiClassType type, PsiElement place) {
place.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
visitElement(expression);
@@ -82,7 +87,7 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
@Override
public void visitThrowStatement(PsiThrowStatement statement) {
super.visitThrowStatement(statement);
List<PsiClassType> actualTypes = ExceptionUtil.getUnhandledExceptions(statement, myPlace);
List<PsiClassType> actualTypes = ExceptionUtil.getUnhandledExceptions(statement, place);
for (PsiClassType actualType : actualTypes) {
if (actualType != null && type.isAssignableFrom(actualType) && myTypeFilter.value(actualType)) {
PsiExpression psiExpression = statement.getException();
@@ -110,7 +115,7 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
super.visitMethodCallExpression(expression);
PsiReference reference = expression.getMethodExpression().getReference();
if (reference != null) {
List<PsiClassType> exceptionTypes = ExceptionUtil.getUnhandledExceptions(expression, myPlace);
List<PsiClassType> exceptionTypes = ExceptionUtil.getUnhandledExceptions(expression, place);
for (final PsiClassType actualType : exceptionTypes) {
if (type.isAssignableFrom(actualType) && myTypeFilter.value(actualType)) {
addOccurrence(expression.getMethodExpression());
@@ -125,7 +130,7 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
super.visitNewExpression(expression);
PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
if (classReference != null) {
List<PsiClassType> exceptionTypes = ExceptionUtil.getUnhandledExceptions(expression, myPlace);
List<PsiClassType> exceptionTypes = ExceptionUtil.getUnhandledExceptions(expression, place);
for (PsiClassType actualType : exceptionTypes) {
if (type.isAssignableFrom(actualType) && myTypeFilter.value(actualType)) {
addOccurrence(classReference);
@@ -134,6 +139,33 @@ public class HighlightExceptionsHandler extends HighlightUsagesHandlerBase<PsiCl
}
}
}
@Override
public void visitResourceExpression(PsiResourceExpression expression) {
super.visitResourceExpression(expression);
List<PsiClassType> exceptionTypes = ExceptionUtil.getUnhandledCloserExceptions(expression, place);
for (PsiClassType actualType : exceptionTypes) {
if (type.isAssignableFrom(actualType) && myTypeFilter.value(actualType)) {
addOccurrence(expression);
break;
}
}
}
@Override
public void visitResourceVariable(PsiResourceVariable variable) {
super.visitResourceVariable(variable);
List<PsiClassType> exceptionTypes = ExceptionUtil.getUnhandledCloserExceptions(variable, place);
for (PsiClassType actualType : exceptionTypes) {
if (type.isAssignableFrom(actualType) && myTypeFilter.value(actualType)) {
PsiIdentifier name = variable.getNameIdentifier();
if (name != null) {
addOccurrence(name);
break;
}
}
}
}
});
}
}
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.stream.Stream;
/**
* @author yole
@@ -56,7 +57,7 @@ public class HighlightExceptionsHandlerFactory extends HighlightUsagesHandlerFac
Collection<PsiClassType> unhandled = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
PsiClassType[] types = unhandled.toArray(new PsiClassType[unhandled.size()]);
return new HighlightExceptionsHandler(editor, file, target, types, tryBlock, Conditions.alwaysTrue());
return new HighlightExceptionsHandler(editor, file, target, types, tryBlock, null, Conditions.alwaysTrue());
}
@Nullable
@@ -66,6 +67,7 @@ public class HighlightExceptionsHandlerFactory extends HighlightUsagesHandlerFac
PsiTryStatement tryStatement = ((PsiCatchSection)parent).getTryStatement();
PsiParameter parameter = ((PsiCatchSection)parent).getParameter();
PsiCodeBlock tryBlock = tryStatement.getTryBlock();
PsiResourceList resourceList = tryStatement.getResourceList();
if (parameter == null || tryBlock == null) return null;
PsiParameter[] parameters = tryStatement.getCatchBlockParameters();
@@ -78,9 +80,12 @@ public class HighlightExceptionsHandlerFactory extends HighlightUsagesHandlerFac
return false;
};
Collection<PsiClassType> unhandled = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
PsiClassType[] types = unhandled.stream().filter(filter::value).toArray(PsiClassType[]::new);
return new HighlightExceptionsHandler(editor, file, target, types, tryBlock, filter);
Stream<PsiClassType> unhandled = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock).stream();
if (resourceList != null) {
unhandled = Stream.concat(unhandled, ExceptionUtil.collectUnhandledExceptions(resourceList, resourceList).stream());
}
PsiClassType[] types = unhandled.filter(filter::value).toArray(PsiClassType[]::new);
return new HighlightExceptionsHandler(editor, file, target, types, tryBlock, resourceList, filter);
}
@Nullable
@@ -94,6 +99,6 @@ public class HighlightExceptionsHandlerFactory extends HighlightUsagesHandlerFac
Collection<PsiClassType> unhandled = ExceptionUtil.collectUnhandledExceptions(body, body);
PsiClassType[] types = unhandled.toArray(new PsiClassType[unhandled.size()]);
return new HighlightExceptionsHandler(editor, file, target, types, body, Conditions.alwaysTrue());
return new HighlightExceptionsHandler(editor, file, target, types, body, null, Conditions.alwaysTrue());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -223,6 +223,32 @@ public class HighlightUsagesHandlerTest extends LightCodeInsightFixtureTestCase
}
}
public void testExceptionsInTryWithResources() {
myFixture.configureByText 'A.java', '''
import java.io.*;
class A {
void test() throws IOException {
try (InputStream in = new FileInputStream("file.name")) { }
<caret>catch (FileNotFoundException e) { throw new FileNotFoundException("no highlighting here"); }
}
}'''.stripIndent()
ctrlShiftF7()
assertRangeText 'FileInputStream', 'catch'
}
public void testExceptionsResourceCloser() {
myFixture.configureByText 'A.java', '''
import java.io.*;
class A {
void test() {
try (InputStream in = new FileInputStream("file.name")) { }
<caret>catch (IOException e) { }
}
}'''.stripIndent()
ctrlShiftF7()
assertRangeText 'in', 'FileInputStream', 'FileInputStream', 'catch'
}
private void configureFile() {
def testName = getTestName(false)
def file = myFixture.copyFileToProject "/codeInsight/highlightUsagesHandler/${testName}.java", "${testName}.java"