mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Try-with-resource support: highlight unhandled exceptions from close()
This commit is contained in:
@@ -247,18 +247,12 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
if (element instanceof PsiResource) {
|
||||
final PsiType resourceType = ((PsiResource)element).getType();
|
||||
if (resourceType instanceof PsiClassType) {
|
||||
final PsiClass resourceClass = ((PsiClassType)resourceType).resolve();
|
||||
if (resourceClass != null) {
|
||||
final List<PsiClassType> unhandled = getUnhandledCloserExceptions(element, resourceClass, topElement);
|
||||
if (unhandledExceptions == null) {
|
||||
unhandledExceptions = unhandled;
|
||||
}
|
||||
else {
|
||||
unhandledExceptions.addAll(unhandled);
|
||||
}
|
||||
}
|
||||
final List<PsiClassType> unhandled = getUnhandledCloserExceptions((PsiResource)element, topElement);
|
||||
if (unhandledExceptions == null) {
|
||||
unhandledExceptions = unhandled;
|
||||
}
|
||||
else {
|
||||
unhandledExceptions.addAll(unhandled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,20 +331,24 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledCloserExceptions(final PsiElement resource,
|
||||
final PsiClass resourceClass,
|
||||
final PsiElement topElement) {
|
||||
final PsiMethod[] closers = resourceClass.findMethodsByName("close", false);
|
||||
for (final PsiMethod method : closers) {
|
||||
if (method.getParameterList().getParametersCount() == 0) {
|
||||
return getUnhandledExceptions(method, resource, topElement, PsiSubstitutor.EMPTY);
|
||||
public static List<PsiClassType> getUnhandledCloserExceptions(final PsiResource resource, final PsiElement topElement) {
|
||||
final PsiType resourceType = resource.getType();
|
||||
if (resourceType instanceof PsiClassType) {
|
||||
final PsiClass resourceClass = ((PsiClassType)resourceType).resolve();
|
||||
if (resourceClass != null) {
|
||||
final PsiMethod[] closers = resourceClass.findMethodsByName("close", false);
|
||||
for (final PsiMethod method : closers) {
|
||||
if (method.getParameterList().getParametersCount() == 0) {
|
||||
return getUnhandledExceptions(method, resource, topElement, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClassType getUnhandledException(PsiThrowStatement throwStatement, PsiElement topElement){
|
||||
public static PsiClassType getUnhandledException(PsiThrowStatement throwStatement, PsiElement topElement) {
|
||||
final PsiExpression exception = throwStatement.getException();
|
||||
if (exception != null) {
|
||||
final PsiType type = exception.getType();
|
||||
|
||||
+47
-24
@@ -36,6 +36,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
@@ -45,6 +46,7 @@ import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.xml.util.XmlStringUtil;
|
||||
import gnu.trove.THashMap;
|
||||
@@ -543,14 +545,16 @@ public class HighlightUtil {
|
||||
return errorResult;
|
||||
}
|
||||
|
||||
public static String getUnhandledExceptionsDescriptor(Collection<PsiClassType> unhandledExceptions) {
|
||||
StringBuilder exceptionsText = new StringBuilder();
|
||||
for (PsiClassType unhandledException : unhandledExceptions) {
|
||||
if (exceptionsText.length() != 0) exceptionsText.append(", ");
|
||||
exceptionsText.append(formatType(unhandledException));
|
||||
}
|
||||
public static String getUnhandledExceptionsDescriptor(final Collection<PsiClassType> unhandled) {
|
||||
return getUnhandledExceptionsDescriptor(unhandled, null);
|
||||
}
|
||||
|
||||
return JavaErrorMessages.message("unhandled.exceptions", exceptionsText.toString(), unhandledExceptions.size());
|
||||
private static String getUnhandledExceptionsDescriptor(final Collection<PsiClassType> unhandled, final String source) {
|
||||
final String exceptions = StringUtil.join(unhandled, new Function<PsiClassType, String>() {
|
||||
@Override public String fun(PsiClassType type) { return formatType(type); }
|
||||
}, ", ");
|
||||
return source != null ? JavaErrorMessages.message("unhandled.close.exceptions", exceptions, unhandled.size(), source)
|
||||
: JavaErrorMessages.message("unhandled.exceptions", exceptions, unhandled.size());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -633,26 +637,45 @@ public class HighlightUtil {
|
||||
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkUnhandledExceptions(PsiElement element, TextRange fixRange) {
|
||||
List<PsiClassType> unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element);
|
||||
HighlightInfo errorResult = null;
|
||||
if (!unhandledExceptions.isEmpty()) {
|
||||
if (fixRange == null) {
|
||||
fixRange = element.getTextRange();
|
||||
}
|
||||
HighlightInfoType highlightType = getUnhandledExceptionHighlightType(element);
|
||||
if (highlightType == null) return null;
|
||||
errorResult = HighlightInfo.createHighlightInfo(highlightType, fixRange, getUnhandledExceptionsDescriptor(unhandledExceptions));
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToCatchFix());
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToThrowsFix(element));
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new SurroundWithTryCatchFix(element));
|
||||
if (unhandledExceptions.size() == 1) {
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new GeneralizeCatchFix(element, unhandledExceptions.get(0)));
|
||||
}
|
||||
}
|
||||
public static HighlightInfo checkUnhandledExceptions(final PsiElement element, TextRange fixRange) {
|
||||
final List<PsiClassType> unhandledExceptions = ExceptionUtil.getUnhandledExceptions(element);
|
||||
if (unhandledExceptions.isEmpty()) return null;
|
||||
|
||||
final HighlightInfoType highlightType = getUnhandledExceptionHighlightType(element);
|
||||
if (highlightType == null) return null;
|
||||
|
||||
if (fixRange == null) fixRange = element.getTextRange();
|
||||
final String description = getUnhandledExceptionsDescriptor(unhandledExceptions);
|
||||
final HighlightInfo errorResult = HighlightInfo.createHighlightInfo(highlightType, fixRange, description);
|
||||
registerUnhandledExceptionFixes(element, errorResult, unhandledExceptions);
|
||||
return errorResult;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkUnhandledCloserExceptions(final PsiResource resource) {
|
||||
final List<PsiClassType> unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null);
|
||||
if (unhandled.isEmpty()) return null;
|
||||
|
||||
final HighlightInfoType highlightType = getUnhandledExceptionHighlightType(resource);
|
||||
if (highlightType == null) return null;
|
||||
|
||||
final String description = getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource");
|
||||
final HighlightInfo highlight = HighlightInfo.createHighlightInfo(highlightType, resource, description);
|
||||
registerUnhandledExceptionFixes(resource, highlight, unhandled);
|
||||
return highlight;
|
||||
}
|
||||
|
||||
private static void registerUnhandledExceptionFixes(final PsiElement element,
|
||||
final HighlightInfo errorResult,
|
||||
final List<PsiClassType> unhandled) {
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToCatchFix());
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new AddExceptionToThrowsFix(element));
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new SurroundWithTryCatchFix(element));
|
||||
if (unhandled.size() == 1) {
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new GeneralizeCatchFix(element, unhandled.get(0)));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static HighlightInfoType getUnhandledExceptionHighlightType(final PsiElement element) {
|
||||
if (!JspPsiUtil.isInJspFile(element)) {
|
||||
|
||||
+7
-6
@@ -902,13 +902,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter));
|
||||
myHolder.add(GenericsHighlightUtil.checkCatchParameterIsClass(parameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PsiResourceList resources = statement.getResourceList();
|
||||
if (resources != null) {
|
||||
for (PsiResource resource : resources.getResources()) {
|
||||
myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visitResource(final PsiResource resource) {
|
||||
myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource));
|
||||
if (!myHolder.hasErrorResults()) {
|
||||
myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -16,6 +16,16 @@ class C {
|
||||
|
||||
try (new MyResource()) { }
|
||||
catch (E1 | E3 ignore) { }
|
||||
|
||||
MyResource r;
|
||||
|
||||
try (<error descr="Unhandled exception from auto-closeable resource: C.E3">r = new MyResource()</error>) { }
|
||||
catch (E1 e) { }
|
||||
|
||||
try (r = <error descr="Unhandled exception: C.E1">new MyResource()</error>) { }
|
||||
catch (E3 e) { }
|
||||
|
||||
try (r = <error descr="Unhandled exception: C.E1">new MyResource()</error>) { }
|
||||
}
|
||||
|
||||
void m2() throws Exception {
|
||||
@@ -27,6 +37,7 @@ class C {
|
||||
void m3() throws Exception {
|
||||
try (MyResource r = new MyResource()) {
|
||||
r.doSomething();
|
||||
/* todo: < error descr="Cannot assign a value to final variable 'r'">r = null</error >;*/
|
||||
}
|
||||
catch (E e) {
|
||||
<error descr="Cannot resolve symbol 'r'">r</error> = null;
|
||||
|
||||
@@ -184,8 +184,10 @@ return.outside.method=Return outside method
|
||||
return.from.void.method=Cannot return a value from a method with void result type
|
||||
missing.return.value=Missing return value
|
||||
|
||||
#{0] - exceptions list (comma separated). {1} - exceptions count in the list
|
||||
#{0} - exceptions list (comma separated), {1} - exceptions count in the list, {2} - exception source
|
||||
unhandled.exceptions=Unhandled {1, choice, 0#exception|2#exceptions}: {0}
|
||||
unhandled.close.exceptions=Unhandled {1, choice, 0#exception|2#exceptions} from {2}: {0}
|
||||
|
||||
variable.already.defined=Variable ''{0}'' is already defined in the scope
|
||||
break.outside.switch.or.loop=Break outside switch or loop
|
||||
continue.outside.loop=Continue outside of loop
|
||||
@@ -212,7 +214,6 @@ duplicate.default.switch.label=Duplicate default label
|
||||
duplicate.switch.label=Duplicate label ''{0}''
|
||||
switch.colon.expected.after.case.label=':' expected
|
||||
|
||||
#See JLS 8.3.2.3
|
||||
illegal.forward.reference=Illegal forward reference
|
||||
|
||||
unknown.class=Unknown class: ''{0}''
|
||||
|
||||
Reference in New Issue
Block a user