lambda: check unhandled exceptions for method references; disable surround with try/catch accordingly (IDEA-98966)

This commit is contained in:
anna
2013-01-14 16:49:05 +01:00
parent 7d80bca02f
commit 1cc7b6ee11
11 changed files with 184 additions and 4 deletions

View File

@@ -1022,6 +1022,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
}
}
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, expression.getTextRange()));
}
}
@Override

View File

@@ -38,10 +38,16 @@ import org.jetbrains.annotations.NotNull;
public class SurroundWithTryCatchFix implements IntentionAction {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.SurroundWithTryCatchFix");
private PsiStatement myStatement;
private PsiStatement myStatement = null;
public SurroundWithTryCatchFix(PsiElement element) {
myStatement = PsiTreeUtil.getNonStrictParentOfType(element, PsiStatement.class);
final PsiMethodReferenceExpression methodReferenceExpression = PsiTreeUtil.getParentOfType(element, PsiMethodReferenceExpression.class, false);
if (methodReferenceExpression == null) {
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class);
if (lambdaExpression == null || lambdaExpression.getBody() instanceof PsiCodeBlock) {
myStatement = PsiTreeUtil.getNonStrictParentOfType(element, PsiStatement.class);
}
}
}
@Override

View File

@@ -240,6 +240,9 @@ public class ExceptionUtil {
PsiCallExpression expression = (PsiCallExpression)element;
unhandledExceptions = getUnhandledExceptions(expression, topElement, includeSelfCalls);
}
else if (element instanceof PsiMethodReferenceExpression) {
unhandledExceptions = getUnhandledExceptions((PsiMethodReferenceExpression)element, topElement);
}
else if (element instanceof PsiThrowStatement) {
PsiThrowStatement statement = (PsiThrowStatement)element;
unhandledExceptions = getUnhandledExceptions(statement, topElement);
@@ -310,6 +313,16 @@ public class ExceptionUtil {
return foundExceptions;
}
private static Collection<PsiClassType> getUnhandledExceptions(PsiMethodReferenceExpression methodReferenceExpression,
PsiElement topElement) {
final JavaResolveResult resolveResult = methodReferenceExpression.advancedResolve(false);
final PsiElement resolve = resolveResult.getElement();
if (resolve instanceof PsiMethod) {
return getUnhandledExceptions((PsiMethod)resolve, methodReferenceExpression, topElement, resolveResult.getSubstitutor());
}
return Collections.emptyList();
}
private static boolean firstStatementIsConstructorCall(PsiCodeBlock constructorBody) {
final PsiStatement[] statements = constructorBody.getStatements();
if (statements.length == 0) return false;
@@ -337,6 +350,12 @@ public class ExceptionUtil {
visitElement(statement);
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
addExceptions(array, getUnhandledExceptions(expression, null));
visitElement(expression);
}
@Override
public void visitResourceVariable(PsiResourceVariable resourceVariable) {
addExceptions(array, getUnhandledCloserExceptions(resourceVariable, null));
@@ -472,12 +491,17 @@ public class ExceptionUtil {
}
private static boolean isArrayClone(PsiMethod method, PsiElement element) {
if (!(element instanceof PsiMethodCallExpression)) return false;
if (!method.getName().equals(CLONE_METHOD_NAME)) return false;
PsiClass containingClass = method.getContainingClass();
if (containingClass == null || !CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) {
return false;
}
if (element instanceof PsiMethodReferenceExpression) {
final PsiMethodReferenceExpression methodCallExpression = (PsiMethodReferenceExpression)element;
final PsiExpression qualifierExpression = methodCallExpression.getQualifierExpression();
return qualifierExpression != null && qualifierExpression.getType() instanceof PsiArrayType;
}
if (!(element instanceof PsiMethodCallExpression)) return false;
PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
@@ -545,7 +569,12 @@ public class ExceptionUtil {
return parent instanceof PsiAnonymousClass && isHandled(parent, exceptionType, topElement);
}
else if (parent instanceof PsiLambdaExpression) {
return true;
final PsiType interfaceType = ((PsiLambdaExpression)parent).getFunctionalInterfaceType();
return isDeclaredBySAMMethod(exceptionType, interfaceType);
}
else if (element instanceof PsiMethodReferenceExpression) {
final PsiType interfaceType = ((PsiMethodReferenceExpression)element).getFunctionalInterfaceType();
return isDeclaredBySAMMethod(exceptionType, interfaceType);
}
else if (parent instanceof PsiClassInitializer) {
if (((PsiClassInitializer)parent).hasModifierProperty(PsiModifier.STATIC)) return false;
@@ -592,6 +621,16 @@ public class ExceptionUtil {
return isHandled(parent, exceptionType, topElement);
}
private static boolean isDeclaredBySAMMethod(PsiClassType exceptionType, PsiType interfaceType) {
if (interfaceType != null) {
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(interfaceType);
if (interfaceMethod != null) {
return isHandledByMethodThrowsClause(interfaceMethod, exceptionType);
}
}
return true;
}
private static boolean areAllConstructorsThrow(final PsiClass aClass, PsiClassType exceptionType) {
if (aClass == null) return false;
final PsiMethod[] constructors = aClass.getConstructors();

View File

@@ -0,0 +1,19 @@
public class ExTest {
public static void maybeThrow(String data) throws Ex {
throw new Ex(data);
}
{
Block<String> b = (t) -> <error descr="Unhandled exception: ExTest.Ex">ExTest.maybeThrow(t)</error>;
}
private static class Ex extends Throwable {
public Ex(String s) {
}
}
}
interface Block<T> {
public void accept(T t);
}

View File

@@ -0,0 +1,19 @@
public class ExTest {
public static void maybeThrow(String data) throws Ex {
throw new Ex(data);
}
{
Block<String> b = <error descr="Unhandled exception: ExTest.Ex">ExTest::maybeThrow</error>;
}
private static class Ex extends Throwable {
public Ex(String s) {
}
}
}
interface Block<T> {
public void accept(T t);
}

View File

@@ -0,0 +1,26 @@
// "Surround with try/catch" "true"
public class ExTest {
public static void maybeThrow(String data) throws Ex {
throw new Ex(data);
}
{
Block<String> b = (t) -> {
try {
return ExTest.maybeThrow(t);
} catch (Ex ex) {
<selection>ex.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.</selection>
}
};
}
private static class Ex extends Throwable {
public Ex(String s) {
}
}
}
interface Block<T> {
public void accept(T t);
}

View File

@@ -0,0 +1,20 @@
// "Surround with try/catch" "true"
public class ExTest {
public static void maybeThrow(String data) throws Ex {
throw new Ex(data);
}
{
Block<String> b = (t) -> { return ExTest.may<caret>beThrow(t);};
}
private static class Ex extends Throwable {
public Ex(String s) {
}
}
}
interface Block<T> {
public void accept(T t);
}

View File

@@ -0,0 +1,20 @@
// "Surround with try/catch" "false"
public class ExTest {
public static void maybeThrow(String data) throws Ex {
throw new Ex(data);
}
{
Block<String> b = (t) -> ExTest.may<caret>beThrow(t);
}
private static class Ex extends Throwable {
public Ex(String s) {
}
}
}
interface Block<T> {
public void accept(T t);
}

View File

@@ -0,0 +1,20 @@
// "Surround with try/catch" "false"
public class ExTest {
public static void maybeThrow(String data) throws Ex {
throw new Ex(data);
}
{
Block<String> b = ExTest::may<caret>beThrow(t);
}
private static class Ex extends Throwable {
public Ex(String s) {
}
}
}
interface Block<T> {
public void accept(T t);
}

View File

@@ -150,6 +150,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testUnhandledExceptions() throws Exception {
doTest();
}
public void testReturnValue() throws Exception {
doTest();
}

View File

@@ -157,6 +157,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest(false);
}
public void testUnhandledExceptions() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTest(false);
}