From fe7611e1298afddd3df67124fc172ccea5f9c45c Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Thu, 10 May 2012 13:49:34 +0400 Subject: [PATCH] highlighting for caught exceptions --- .../plugins/groovy/GroovyBundle.properties | 3 + .../groovy/annotator/GroovyAnnotator.java | 65 +++++++++++++++++++ .../groovy/lang/GroovyHighlightingTest.groovy | 48 ++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index 7aa4e6d9fdc7..8e7de64218df 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -308,3 +308,6 @@ closure.is.too.complex.to.analyze=Closure is complex to analyze.\nTypes of local create.parameter.from.usage=Create Parameter ''{0}'' wrong.number.of.type.arguments=Wrong number of type arguments\: {0}; required\: {1} type.argument.0.is.not.in.its.bound.should.extend.1=Type parameter ''{0}'' is not in its bound; should extend ''{1}'' +catch.statement.parameter.type.should.be.a.subclass.of.throwable=Catch statement parameter type should be a subclass of Throwable +exception.0.has.already.been.caught=Exception ''{0}'' has already been caught +unnecessary.type=Unnecessary exception ''{0}''. ''{1}'' is already declared diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index ca1e094f3b91..af683cbe996c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -227,6 +227,71 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } + @Override + public void visitTryStatement(GrTryCatchStatement statement) { + final GrCatchClause[] clauses = statement.getCatchClauses(); + List usedExceptions = new ArrayList(); + + final PsiClassType throwable = PsiType.getJavaLangThrowable(statement.getManager(), statement.getResolveScope()); + + for (GrCatchClause clause : clauses) { + final GrParameter parameter = clause.getParameter(); + if (parameter == null) continue; + + final GrTypeElement typeElement = parameter.getTypeElementGroovy(); + + PsiType type = typeElement != null ? typeElement.getType() : null; + if (type == null) { + type = throwable; + } + + if (!throwable.isAssignableFrom(type)) { + LOG.assertTrue(typeElement != null); + myHolder.createErrorAnnotation(typeElement, + GroovyBundle.message("catch.statement.parameter.type.should.be.a.subclass.of.throwable")); + continue; + } + + if (typeElement instanceof GrDisjunctionTypeElement) { + final GrTypeElement[] elements = ((GrDisjunctionTypeElement)typeElement).getTypeElements(); + PsiType[] types = new PsiType[elements.length]; + for (int i = 0; i < elements.length; i++) { + types[i] = elements[i].getType(); + } + + List usedInsideDisjunction = new ArrayList(); + for (int i = 0; i < types.length; i++) { + if (checkExceptionUsed(usedExceptions, parameter, elements[i], types[i])) { + usedInsideDisjunction.add(types[i]); + for (int j = 0; j < types.length; j++) { + if (i != j && types[j].isAssignableFrom(types[i])) { + myHolder.createWarningAnnotation(elements[i], GroovyBundle.message("unnecessary.type", types[i].getCanonicalText(), + types[j].getCanonicalText())); + } + } + } + } + + usedExceptions.addAll(usedInsideDisjunction); + } + else { + if (checkExceptionUsed(usedExceptions, parameter, typeElement, type)) { + usedExceptions.add(type); + } + } + } + } + + private boolean checkExceptionUsed(List usedExceptions, GrParameter parameter, GrTypeElement typeElement, PsiType type) { + for (PsiType exception : usedExceptions) { + if (exception.isAssignableFrom(type)) { + myHolder.createWarningAnnotation(typeElement != null ? typeElement : parameter.getNameIdentifierGroovy(), GroovyBundle.message("exception.0.has.already.been.caught", type.getCanonicalText())); + return false; + } + } + return true; + } + @Override public void visitReferenceExpression(final GrReferenceExpression referenceExpression) { checkStringNameIdentifier(referenceExpression); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index 2e24f7a14738..ec7ff165c658 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -936,4 +936,52 @@ def test() { } ''', GroovyAssignabilityCheckInspection) } + + void testTryCatch1() { + testHighlighting('''\ +try {} +catch (Exception e){} +catch (IOException e){} +''') + } + + void testTryCatch2() { + testHighlighting('''\ +try {} +catch (e){} +catch (e){} +''') + } + + void testTryCatch3() { + testHighlighting('''\ +try {} +catch (e){} +catch (IOException e){} +''') + } + + void testTryCatch4() { + testHighlighting('''\ +try {} +catch (Exception | IOException e){} +''') + } + + void testTryCatch5() { + testHighlighting('''\ +try {} +catch (RuntimeException | IOException e){} +catch (NullPointerException e){} +''') + } + + void testTryCatch6() { + testHighlighting('''\ +try {} +catch (NullPointerException | IOException e){} +catch (ClassNotFoundException | NullPointerException e){} +''') + } + } \ No newline at end of file