mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
exceptions declared by try with resources should collect all close methods from the resource class and choose exceptions in the intersection (IDEA-158762)
This commit is contained in:
+17
-12
@@ -16,6 +16,7 @@
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.*;
|
||||
import com.intellij.codeInspection.dataFlow.value.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -1041,9 +1042,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
((PsiResourceExpression)resource).getExpression().accept(this);
|
||||
}
|
||||
|
||||
PsiMethod closer = PsiUtil.getResourceCloserMethod(resource);
|
||||
if (closer != null) {
|
||||
addMethodThrows(closer, null);
|
||||
final List<PsiClassType> closerExceptions = ExceptionUtil.getCloserExceptions(resource);
|
||||
if (!closerExceptions.isEmpty()) {
|
||||
addThrows(null, findNextCatch(false), closerExceptions.toArray(new PsiClassType[closerExceptions.size()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1411,15 +1412,19 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
CatchDescriptor cd = findNextCatch(false);
|
||||
if (method != null) {
|
||||
PsiClassType[] refs = method.getThrowsList().getReferencedTypes();
|
||||
for (PsiClassType ref : refs) {
|
||||
pushUnknown();
|
||||
ConditionalGotoInstruction cond = new ConditionalGotoInstruction(null, false, null);
|
||||
addInstruction(cond);
|
||||
addInstruction(new EmptyStackInstruction());
|
||||
initException(ref, cd);
|
||||
addThrowCode(cd, explicitCall);
|
||||
cond.setOffset(myCurrentFlow.getInstructionCount());
|
||||
}
|
||||
addThrows(explicitCall, cd, refs);
|
||||
}
|
||||
}
|
||||
|
||||
private void addThrows(@Nullable PsiElement explicitCall, CatchDescriptor cd, PsiClassType[] refs) {
|
||||
for (PsiClassType ref : refs) {
|
||||
pushUnknown();
|
||||
ConditionalGotoInstruction cond = new ConditionalGotoInstruction(null, false, null);
|
||||
addInstruction(cond);
|
||||
addInstruction(new EmptyStackInstruction());
|
||||
initException(ref, cd);
|
||||
addThrowCode(cd, explicitCall);
|
||||
cond.setOffset(myCurrentFlow.getInstructionCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-6
@@ -100,11 +100,6 @@ public class TryWithResourcesPostfixTemplate extends PostfixTemplate {
|
||||
@NotNull
|
||||
private static Collection<PsiClassType> getUnhandled(@NotNull PsiExpression expression) {
|
||||
assert expression.getType() != null;
|
||||
PsiMethod methodCloser = PsiUtil.getResourceCloserMethodForType((PsiClassType)expression.getType());
|
||||
PsiSubstitutor substitutor = PsiUtil.resolveGenericsClassInType(expression.getType()).getSubstitutor();
|
||||
|
||||
return methodCloser != null
|
||||
? ExceptionUtil.getUnhandledExceptions(methodCloser, expression, null, substitutor)
|
||||
: Collections.<PsiClassType>emptyList();
|
||||
return ExceptionUtil.getUnhandledCloserExceptions(expression, null, expression.getType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1137,20 +1137,9 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
return name != null && IGNORED_NAMES.contains(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getResourceCloserMethod(@NotNull PsiResourceListElement resource) {
|
||||
PsiType resourceType = resource.getType();
|
||||
return resourceType instanceof PsiClassType ? getResourceCloserMethodForType((PsiClassType)resourceType) : null;
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #getResourceCloserMethod(PsiResourceListElement)} (to be removed in IDEA 17) */
|
||||
@SuppressWarnings("unused")
|
||||
public static PsiMethod getResourceCloserMethod(@NotNull PsiResourceVariable resource) {
|
||||
return getResourceCloserMethod((PsiResourceListElement)resource);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getResourceCloserMethodForType(@NotNull final PsiClassType resourceType) {
|
||||
public static PsiMethod[] getResourceCloserMethodsForType(@NotNull final PsiClassType resourceType) {
|
||||
final PsiClass resourceClass = resourceType.resolve();
|
||||
if (resourceClass == null) return null;
|
||||
|
||||
@@ -1162,7 +1151,10 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
if (JavaClassSupers.getInstance().getSuperClassSubstitutor(autoCloseable, resourceClass, resourceType.getResolveScope(), PsiSubstitutor.EMPTY) == null) return null;
|
||||
|
||||
final PsiMethod[] closes = autoCloseable.findMethodsByName("close", false);
|
||||
return closes.length == 1 ? resourceClass.findMethodBySignature(closes[0], true) : null;
|
||||
if (closes.length == 1) {
|
||||
return resourceClass.findMethodsBySignature(closes[0], true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -38,8 +38,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.openapi.util.Pair.pair;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
@@ -533,38 +531,66 @@ public class ExceptionUtil {
|
||||
if (psiType instanceof PsiClassType) {
|
||||
ex.add((PsiClassType)psiType);
|
||||
}
|
||||
else if (psiType instanceof PsiCapturedWildcardType) {
|
||||
final PsiCapturedWildcardType capturedWildcardType = (PsiCapturedWildcardType)psiType;
|
||||
final PsiType upperBound = capturedWildcardType.getUpperBound();
|
||||
if (upperBound instanceof PsiClassType) {
|
||||
ex.add((PsiClassType)upperBound);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getCloserExceptions(@NotNull PsiResourceListElement resource) {
|
||||
Pair<PsiMethod, PsiSubstitutor> closer = resolveCloser(resource);
|
||||
return closer != null ? getExceptionsByMethod(closer.first, closer.second, resource) : Collections.<PsiClassType>emptyList();
|
||||
List<PsiClassType> ex = getExceptionsFromClose(resource);
|
||||
return ex != null ? ex : Collections.<PsiClassType>emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledCloserExceptions(@NotNull PsiResourceListElement resource, @Nullable PsiElement topElement) {
|
||||
Pair<PsiMethod, PsiSubstitutor> closer = resolveCloser(resource);
|
||||
return closer != null ? getUnhandledExceptions(closer.first, resource, topElement, closer.second) : Collections.<PsiClassType>emptyList();
|
||||
final PsiType type = resource.getType();
|
||||
return getUnhandledCloserExceptions(resource, topElement, type);
|
||||
}
|
||||
|
||||
private static Pair<PsiMethod, PsiSubstitutor> resolveCloser(PsiResourceListElement resource) {
|
||||
PsiMethod method = PsiUtil.getResourceCloserMethod(resource);
|
||||
if (method != null) {
|
||||
PsiClass closerClass = method.getContainingClass();
|
||||
if (closerClass != null) {
|
||||
PsiClassType.ClassResolveResult resourceType = PsiUtil.resolveGenericsClassInType(resource.getType());
|
||||
if (resourceType != null) {
|
||||
PsiClass resourceClass = resourceType.getElement();
|
||||
if (resourceClass != null) {
|
||||
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(closerClass, resourceClass, resourceType.getSubstitutor());
|
||||
if (substitutor != null) {
|
||||
return pair(method, substitutor);
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledCloserExceptions(PsiElement place, @Nullable PsiElement topElement, PsiType type) {
|
||||
List<PsiClassType> ex = type instanceof PsiClassType ? getExceptionsFromClose(type, place.getResolveScope()) : null;
|
||||
return ex != null ? getUnhandledExceptions(place, topElement, PsiSubstitutor.EMPTY, ex.toArray(new PsiClassType[ex.size()])) : Collections.<PsiClassType>emptyList();
|
||||
}
|
||||
|
||||
private static List<PsiClassType> getExceptionsFromClose(PsiResourceListElement resource) {
|
||||
final PsiType type = resource.getType();
|
||||
return type instanceof PsiClassType ? getExceptionsFromClose(type, resource.getResolveScope()) : null;
|
||||
}
|
||||
|
||||
private static List<PsiClassType> getExceptionsFromClose(PsiType type, GlobalSearchScope scope) {
|
||||
PsiClassType.ClassResolveResult resourceType = PsiUtil.resolveGenericsClassInType(type);
|
||||
PsiClass resourceClass = resourceType.getElement();
|
||||
if (resourceClass == null) return null;
|
||||
|
||||
PsiMethod[] methods = PsiUtil.getResourceCloserMethodsForType((PsiClassType)type);
|
||||
if (methods != null) {
|
||||
List<PsiClassType> ex = null;
|
||||
for (PsiMethod method : methods) {
|
||||
PsiClass closerClass = method.getContainingClass();
|
||||
if (closerClass != null) {
|
||||
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(closerClass, resourceClass, resourceType.getSubstitutor());
|
||||
if (substitutor != null) {
|
||||
final PsiClassType[] exceptionTypes = method.getThrowsList().getReferencedTypes();
|
||||
if (exceptionTypes.length == 0) return Collections.emptyList();
|
||||
|
||||
if (ex == null) {
|
||||
ex = collectSubstituted(substitutor, exceptionTypes, scope);
|
||||
}
|
||||
else {
|
||||
retainExceptions(ex, collectSubstituted(substitutor, exceptionTypes, scope));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
import java.io.IOException;
|
||||
|
||||
class Ex extends Exception {}
|
||||
|
||||
interface IOCloseable {
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
||||
interface ExCloseable {
|
||||
void close() throws Ex;
|
||||
}
|
||||
|
||||
interface NoExCloseable {
|
||||
void close();
|
||||
}
|
||||
|
||||
interface TCloseable<T extends Throwable> {
|
||||
void close() throws T;
|
||||
}
|
||||
|
||||
interface I1 extends AutoCloseable, IOCloseable {}
|
||||
interface I1R extends IOCloseable, AutoCloseable {}
|
||||
interface I2 extends AutoCloseable, IOCloseable, ExCloseable {}
|
||||
interface I3 extends AutoCloseable, NoExCloseable {}
|
||||
interface I3R extends NoExCloseable, AutoCloseable {}
|
||||
|
||||
interface IT extends AutoCloseable, TCloseable<IOException> {}
|
||||
|
||||
class Main {
|
||||
{
|
||||
try (<error descr="Unhandled exception from auto-closeable resource: java.io.IOException">I1 i1 = null</error>) {}
|
||||
try (I1 i11 = null) {
|
||||
} catch (IOException e){}
|
||||
try (I1R i11r = null) {
|
||||
} catch (IOException e){}
|
||||
|
||||
try (I2 i2 = null) {}
|
||||
try (I2 i21 = null) {
|
||||
} catch (<error descr="Exception 'java.io.IOException' is never thrown in the corresponding try block">IOException e</error>) {}
|
||||
try (I2 i22 = null) {
|
||||
} catch (<error descr="Exception 'Ex' is never thrown in the corresponding try block">Ex e</error>) {}
|
||||
|
||||
try (I3 i3 = null) {}
|
||||
try (I3R i3r = null) {}
|
||||
|
||||
try (<error descr="Unhandled exception from auto-closeable resource: java.io.IOException">IT it = null</error>) {}
|
||||
}
|
||||
}
|
||||
+1
@@ -180,6 +180,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testUncheckedExtendedWarnings() { doTest(true, false); }
|
||||
public void testInaccessibleInferredTypeForVarargsArgument() { doTest(false, false);}
|
||||
public void testRuntimeClassCast() { doTest(true, false);}
|
||||
public void testTryWithResourcesWithMultipleCloseInterfaces() { doTest(false, false);}
|
||||
|
||||
public void testJavaUtilCollections_NoVerify() throws Exception {
|
||||
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
|
||||
|
||||
+4
-24
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.siyeh.ig.psiutils;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -48,8 +48,7 @@ public class ExceptionUtils {
|
||||
if (element instanceof PsiResourceList) {
|
||||
final PsiResourceList resourceList = (PsiResourceList)element;
|
||||
for (PsiResourceListElement resource : resourceList) {
|
||||
final PsiMethod method = PsiUtil.getResourceCloserMethod(resource);
|
||||
collectExceptionsThrown(method, PsiSubstitutor.EMPTY, out);
|
||||
out.addAll(ExceptionUtil.getCloserExceptions(resource));
|
||||
}
|
||||
}
|
||||
final ExceptionsThrownVisitor visitor = new ExceptionsThrownVisitor(out);
|
||||
@@ -202,26 +201,6 @@ public class ExceptionUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void collectExceptionsThrown(@Nullable PsiMethod method, @NotNull PsiSubstitutor substitutor,
|
||||
@NotNull Set<PsiClassType> out) {
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
for (PsiClassType type : method.getThrowsList().getReferencedTypes()) {
|
||||
final PsiType substitute = substitutor.substitute(type);
|
||||
if (substitute instanceof PsiClassType) {
|
||||
out.add((PsiClassType)substitute);
|
||||
}
|
||||
else if (substitute instanceof PsiCapturedWildcardType) {
|
||||
final PsiCapturedWildcardType capturedWildcardType = (PsiCapturedWildcardType)substitute;
|
||||
final PsiType upperBound = capturedWildcardType.getUpperBound();
|
||||
if (upperBound instanceof PsiClassType) {
|
||||
out.add((PsiClassType)upperBound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<PsiType> getExceptionTypesHandled(PsiTryStatement statement) {
|
||||
final Set<PsiType> out = new HashSet<>(5);
|
||||
for (PsiParameter parameter : statement.getCatchBlockParameters()) {
|
||||
@@ -258,7 +237,8 @@ public class ExceptionUtils {
|
||||
if (!(target instanceof PsiMethod)) {
|
||||
return;
|
||||
}
|
||||
collectExceptionsThrown((PsiMethod)target, resolveResult.getSubstitutor(), m_exceptionsThrown);
|
||||
final PsiClassType[] referencedTypes = ((PsiMethod)target).getThrowsList().getReferencedTypes();
|
||||
m_exceptionsThrown.addAll(ExceptionUtil.collectSubstituted(resolveResult.getSubstitutor(), referencedTypes, callExpression.getResolveScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user