mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] adds support for Java 9's improved try-with-resources (IDEA-140266)
PSI, parser, highlighting, exception analysis, control flow, completion.
This commit is contained in:
+45
-11
@@ -770,16 +770,15 @@ public class HighlightUtil extends HighlightUtilBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkUnhandledCloserExceptions(@NotNull final PsiResourceVariable resource) {
|
||||
final List<PsiClassType> unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null);
|
||||
static HighlightInfo checkUnhandledCloserExceptions(@NotNull PsiResourceListElement resource) {
|
||||
List<PsiClassType> unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null);
|
||||
if (unhandled.isEmpty()) return null;
|
||||
|
||||
final HighlightInfoType highlightType = getUnhandledExceptionHighlightType(resource);
|
||||
HighlightInfoType highlightType = getUnhandledExceptionHighlightType(resource);
|
||||
if (highlightType == null) return null;
|
||||
|
||||
final String description = getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource");
|
||||
final HighlightInfo highlight =
|
||||
HighlightInfo.newHighlightInfo(highlightType).range(resource).descriptionAndTooltip(description).create();
|
||||
String description = getUnhandledExceptionsDescriptor(unhandled, "auto-closeable resource");
|
||||
HighlightInfo highlight = HighlightInfo.newHighlightInfo(highlightType).range(resource).descriptionAndTooltip(description).create();
|
||||
registerUnhandledExceptionFixes(resource, highlight, unhandled);
|
||||
return highlight;
|
||||
}
|
||||
@@ -1715,15 +1714,49 @@ public class HighlightUtil extends HighlightUtilBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull final PsiResourceVariable resource) {
|
||||
final PsiType type = resource.getType();
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(resource.getProject()).getElementFactory();
|
||||
final PsiClassType autoCloseable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, resource.getResolveScope());
|
||||
static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull PsiResourceListElement resource) {
|
||||
PsiType type = resource.getType();
|
||||
if (type == null) return null;
|
||||
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(resource.getProject()).getElementFactory();
|
||||
PsiClassType autoCloseable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, resource.getResolveScope());
|
||||
if (TypeConversionUtil.isAssignable(autoCloseable, type)) return null;
|
||||
|
||||
return createIncompatibleTypeHighlightInfo(autoCloseable, type, resource.getTextRange(), 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkResourceVariableIsFinal(@NotNull PsiResourceExpression resource) {
|
||||
PsiExpression expression = resource.getExpression();
|
||||
|
||||
if (expression instanceof PsiThisExpression) return null;
|
||||
|
||||
if (expression instanceof PsiReferenceExpression) {
|
||||
PsiElement target = ((PsiReferenceExpression)expression).resolve();
|
||||
if (target == null) return null;
|
||||
|
||||
if (target instanceof PsiVariable) {
|
||||
PsiVariable variable = (PsiVariable)target;
|
||||
|
||||
PsiModifierList modifierList = variable.getModifierList();
|
||||
if (modifierList != null && modifierList.hasModifierProperty(PsiModifier.FINAL)) return null;
|
||||
|
||||
PsiElement scope = null;
|
||||
if (variable instanceof PsiParameter) scope = ((PsiParameter)variable).getDeclarationScope();
|
||||
else if (variable instanceof PsiResourceVariable) scope = variable.getParent().getParent();
|
||||
else if (variable instanceof PsiLocalVariable) scope = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
|
||||
if (scope != null) {
|
||||
if (HighlightControlFlowUtil.isEffectivelyFinal(variable, scope, null)) return null;
|
||||
}
|
||||
}
|
||||
|
||||
String text = JavaErrorMessages.message("resource.variable.must.be.final");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(text).create();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Collection<HighlightInfo> checkArrayInitializer(final PsiExpression initializer, PsiType type) {
|
||||
if (!(initializer instanceof PsiArrayInitializerExpression)) return null;
|
||||
@@ -2913,7 +2946,8 @@ public class HighlightUtil extends HighlightUtilBase {
|
||||
METHOD_REFERENCES(LanguageLevel.JDK_1_8, "feature.method.references"),
|
||||
LAMBDA_EXPRESSIONS(LanguageLevel.JDK_1_8, "feature.lambda.expressions"),
|
||||
TYPE_ANNOTATIONS(LanguageLevel.JDK_1_8, "feature.type.annotations"),
|
||||
RECEIVERS(LanguageLevel.JDK_1_8, "feature.type.receivers");
|
||||
RECEIVERS(LanguageLevel.JDK_1_8, "feature.type.receivers"),
|
||||
REFS_AS_RESOURCE(LanguageLevel.JDK_1_9, "feature.try.with.resources.refs");
|
||||
|
||||
private final LanguageLevel level;
|
||||
private final String key;
|
||||
|
||||
+13
-4
@@ -1482,10 +1482,19 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResourceVariable(PsiResourceVariable variable) {
|
||||
super.visitResourceVariable(variable);
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(variable));
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(variable));
|
||||
public void visitResourceVariable(PsiResourceVariable resource) {
|
||||
super.visitResourceVariable(resource);
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource));
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResourceExpression(PsiResourceExpression resource) {
|
||||
super.visitResourceExpression(resource);
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(checkFeature(resource, Feature.REFS_AS_RESOURCE));
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkResourceVariableIsFinal(resource));
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource));
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+16
-7
@@ -350,8 +350,10 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
else if (parent instanceof PsiTryStatement) {
|
||||
PsiResourceList list = ((PsiTryStatement)parent).getResourceList();
|
||||
if (list != null) {
|
||||
for (PsiResourceVariable variable : list.getResourceVariables()) {
|
||||
myCurrentFlow.removeVariable(variable);
|
||||
for (PsiResourceListElement resource : list) {
|
||||
if (resource instanceof PsiResourceVariable) {
|
||||
myCurrentFlow.removeVariable((PsiVariable)resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1029,12 +1031,19 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
@Override
|
||||
public void visitResourceList(PsiResourceList resourceList) {
|
||||
for (PsiResourceVariable variable : resourceList.getResourceVariables()) {
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer != null) {
|
||||
initializeVariable(variable, initializer);
|
||||
for (PsiResourceListElement resource : resourceList) {
|
||||
if (resource instanceof PsiResourceVariable) {
|
||||
PsiResourceVariable variable = (PsiResourceVariable)resource;
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer != null) {
|
||||
initializeVariable(variable, initializer);
|
||||
}
|
||||
}
|
||||
PsiMethod closer = PsiUtil.getResourceCloserMethod(variable);
|
||||
else if (resource instanceof PsiResourceExpression) {
|
||||
((PsiResourceExpression)resource).getExpression().accept(this);
|
||||
}
|
||||
|
||||
PsiMethod closer = PsiUtil.getResourceCloserMethod(resource);
|
||||
if (closer != null) {
|
||||
addMethodThrows(closer, null);
|
||||
}
|
||||
|
||||
@@ -61,10 +61,11 @@ public class PreferByKindWeigher extends LookupElementWeigher {
|
||||
static final ElementPattern<PsiElement> INSIDE_METHOD_THROWS_CLAUSE =
|
||||
psiElement().afterLeaf(PsiKeyword.THROWS, ",").inside(psiElement(JavaElementType.THROWS_LIST));
|
||||
|
||||
static final ElementPattern<PsiElement> IN_RESOURCE_TYPE =
|
||||
psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).
|
||||
withParent(psiElement(PsiTypeElement.class).
|
||||
withParent(or(psiElement(PsiResourceVariable.class), psiElement(PsiResourceList.class)))));
|
||||
static final ElementPattern<PsiElement> IN_RESOURCE =
|
||||
psiElement().withParent(or(
|
||||
psiElement(PsiJavaCodeReferenceElement.class).withParent(PsiTypeElement.class).
|
||||
withSuperParent(2, or(psiElement(PsiResourceVariable.class), psiElement(PsiResourceList.class))),
|
||||
psiElement(PsiReferenceExpression.class).withParent(PsiResourceExpression.class)));
|
||||
|
||||
private final CompletionType myCompletionType;
|
||||
private final PsiElement myPosition;
|
||||
@@ -115,7 +116,7 @@ public class PreferByKindWeigher extends LookupElementWeigher {
|
||||
};
|
||||
}
|
||||
|
||||
if (IN_RESOURCE_TYPE.accepts(position)) {
|
||||
if (IN_RESOURCE.accepts(position)) {
|
||||
return new Condition<PsiClass>() {
|
||||
@Override
|
||||
public boolean value(PsiClass psiClass) {
|
||||
|
||||
@@ -312,6 +312,10 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
|
||||
visitLocalVariable(variable);
|
||||
}
|
||||
|
||||
public void visitResourceExpression(PsiResourceExpression expression) {
|
||||
visitElement(expression);
|
||||
}
|
||||
|
||||
public void visitTypeElement(PsiTypeElement type) {
|
||||
visitElement(type);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a resource expression of enhanced try-with-resources statement introduced in JDK 9.
|
||||
*
|
||||
* @see PsiResourceList
|
||||
* @since 15
|
||||
*/
|
||||
public interface PsiResourceExpression extends PsiResourceListElement {
|
||||
@NotNull
|
||||
PsiExpression getExpression();
|
||||
}
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -25,9 +23,10 @@ import java.util.List;
|
||||
* @see PsiTryStatement#getResourceList()
|
||||
* @since 10.5
|
||||
*/
|
||||
public interface PsiResourceList extends PsiElement {
|
||||
public interface PsiResourceList extends PsiElement, Iterable<PsiResourceListElement> {
|
||||
int getResourceVariablesCount();
|
||||
|
||||
@NotNull
|
||||
/** @deprecated use {@link #iterator()} (to be removed in IDEA 17) */
|
||||
@SuppressWarnings("unused")
|
||||
List<PsiResourceVariable> getResourceVariables();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Common interface for {@link PsiResourceVariable} and {@link PsiResourceExpression}.
|
||||
*
|
||||
* @since 15
|
||||
*/
|
||||
public interface PsiResourceListElement extends PsiElement {
|
||||
@Nullable
|
||||
PsiType getType();
|
||||
}
|
||||
@@ -20,10 +20,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* Represents a resource variable of try-with-resources statement (automatic resource management) introduced in JDK 7.
|
||||
*
|
||||
* @see PsiResourceList#getResourceVariables()
|
||||
* @see PsiResourceList
|
||||
* @since 10.5
|
||||
*/
|
||||
public interface PsiResourceVariable extends PsiLocalVariable {
|
||||
public interface PsiResourceVariable extends PsiLocalVariable, PsiResourceListElement {
|
||||
@NotNull
|
||||
PsiElement[] getDeclarationScope();
|
||||
}
|
||||
|
||||
@@ -1126,10 +1126,15 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getResourceCloserMethod(@NotNull final PsiResourceVariable resource) {
|
||||
final PsiType resourceType = resource.getType();
|
||||
if (!(resourceType instanceof PsiClassType)) return null;
|
||||
return getResourceCloserMethodForType((PsiClassType)resourceType);
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -118,14 +118,19 @@ public class ExceptionUtil {
|
||||
else if (element instanceof PsiTryStatement) {
|
||||
return getTryExceptions((PsiTryStatement)element);
|
||||
}
|
||||
else if (element instanceof PsiResourceVariable) {
|
||||
final PsiResourceVariable variable = (PsiResourceVariable)element;
|
||||
final List<PsiClassType> types = ContainerUtil.newArrayList();
|
||||
addExceptions(types, getCloserExceptions(variable));
|
||||
final PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer != null) addExceptions(types, getThrownExceptions(initializer));
|
||||
else if (element instanceof PsiResourceListElement) {
|
||||
List<PsiClassType> types = ContainerUtil.newArrayList();
|
||||
addExceptions(types, getCloserExceptions((PsiResourceListElement)element));
|
||||
if (element instanceof PsiResourceVariable) {
|
||||
PsiResourceVariable variable = (PsiResourceVariable)element;
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer != null) {
|
||||
addExceptions(types, getThrownExceptions(initializer));
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
return getThrownExceptions(element.getChildren());
|
||||
}
|
||||
|
||||
@@ -135,8 +140,8 @@ public class ExceptionUtil {
|
||||
|
||||
PsiResourceList resourceList = tryStatement.getResourceList();
|
||||
if (resourceList != null) {
|
||||
for (PsiResourceVariable variable : resourceList.getResourceVariables()) {
|
||||
addExceptions(array, getUnhandledCloserExceptions(variable, resourceList));
|
||||
for (PsiResourceListElement resource : resourceList) {
|
||||
addExceptions(array, getUnhandledCloserExceptions(resource, resourceList));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,16 +308,10 @@ public class ExceptionUtil {
|
||||
}
|
||||
unhandledExceptions = unhandled;
|
||||
}
|
||||
|
||||
if (element instanceof PsiResourceVariable) {
|
||||
final List<PsiClassType> unhandled = getUnhandledCloserExceptions((PsiResourceVariable)element, topElement);
|
||||
else if (element instanceof PsiResourceListElement) {
|
||||
final List<PsiClassType> unhandled = getUnhandledCloserExceptions((PsiResourceListElement)element, topElement);
|
||||
if (!unhandled.isEmpty()) {
|
||||
if (unhandledExceptions == null) {
|
||||
unhandledExceptions = ContainerUtil.newArrayList(unhandled);
|
||||
}
|
||||
else {
|
||||
unhandledExceptions.addAll(unhandled);
|
||||
}
|
||||
unhandledExceptions = ContainerUtil.newArrayList(unhandled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,6 +355,7 @@ public class ExceptionUtil {
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledExceptions(final @NotNull PsiElement[] elements) {
|
||||
final List<PsiClassType> array = ContainerUtil.newArrayList();
|
||||
|
||||
final PsiElementVisitor visitor = new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitCallExpression(@NotNull PsiCallExpression expression) {
|
||||
@@ -377,9 +377,15 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResourceVariable(@NotNull PsiResourceVariable resourceVariable) {
|
||||
addExceptions(array, getUnhandledCloserExceptions(resourceVariable, null));
|
||||
visitElement(resourceVariable);
|
||||
public void visitResourceVariable(@NotNull PsiResourceVariable resource) {
|
||||
addExceptions(array, getUnhandledCloserExceptions((PsiResourceListElement)resource, null));
|
||||
visitElement(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitResourceExpression(@NotNull PsiResourceExpression resource) {
|
||||
addExceptions(array, getUnhandledCloserExceptions(resource, null));
|
||||
visitElement(resource);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -392,18 +398,6 @@ public class ExceptionUtil {
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledExceptions(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiCallExpression) {
|
||||
PsiCallExpression expression = (PsiCallExpression)element;
|
||||
return getUnhandledExceptions(expression, null);
|
||||
}
|
||||
else if (element instanceof PsiThrowStatement) {
|
||||
PsiThrowStatement throwStatement = (PsiThrowStatement)element;
|
||||
return getUnhandledExceptions(throwStatement, null);
|
||||
}
|
||||
else if (element instanceof PsiResourceVariable) {
|
||||
return getUnhandledCloserExceptions((PsiResourceVariable)element, null);
|
||||
}
|
||||
|
||||
return getUnhandledExceptions(new PsiElement[]{element});
|
||||
}
|
||||
|
||||
@@ -532,19 +526,31 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getCloserExceptions(@NotNull PsiResourceVariable resource) {
|
||||
public static List<PsiClassType> getCloserExceptions(@NotNull PsiResourceListElement resource) {
|
||||
PsiMethod method = PsiUtil.getResourceCloserMethod(resource);
|
||||
PsiSubstitutor substitutor = PsiUtil.resolveGenericsClassInType(resource.getType()).getSubstitutor();
|
||||
return method != null ? getExceptionsByMethod(method, substitutor, resource) : Collections.<PsiClassType>emptyList();
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #getCloserExceptions(PsiResourceListElement)} (to be removed in IDEA 16) */
|
||||
@SuppressWarnings("unused")
|
||||
public static List<PsiClassType> getCloserExceptions(@NotNull PsiResourceVariable resource) {
|
||||
return getCloserExceptions((PsiResourceListElement)resource);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledCloserExceptions(@NotNull PsiResourceVariable resource, @Nullable PsiElement topElement) {
|
||||
public static List<PsiClassType> getUnhandledCloserExceptions(@NotNull PsiResourceListElement resource, @Nullable PsiElement topElement) {
|
||||
PsiMethod method = PsiUtil.getResourceCloserMethod(resource);
|
||||
PsiSubstitutor substitutor = PsiUtil.resolveGenericsClassInType(resource.getType()).getSubstitutor();
|
||||
return method != null ? getUnhandledExceptions(method, resource, topElement, substitutor) : Collections.<PsiClassType>emptyList();
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #getUnhandledCloserExceptions(PsiResourceListElement, PsiElement)} (to be removed in IDEA 16) */
|
||||
@SuppressWarnings("unused")
|
||||
public static List<PsiClassType> getUnhandledCloserExceptions(@NotNull PsiResourceVariable resource, @Nullable PsiElement topElement) {
|
||||
return getUnhandledCloserExceptions((PsiResourceListElement)resource, topElement);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledExceptions(@NotNull PsiThrowStatement throwStatement, @Nullable PsiElement topElement) {
|
||||
List<PsiClassType> unhandled = new SmartList<PsiClassType>();
|
||||
@@ -574,7 +580,7 @@ public class ExceptionUtil {
|
||||
if (expression != null) {
|
||||
final PsiType type = expression.getType();
|
||||
if (type != null) {
|
||||
return Arrays.asList(type);
|
||||
return Collections.singletonList(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ public class DeclarationParser {
|
||||
JavaTokenType.RPARENTH, JavaTokenType.LBRACE, JavaTokenType.ARROW);
|
||||
private static final TokenSet TYPE_START = TokenSet.orSet(
|
||||
ElementType.PRIMITIVE_TYPE_BIT_SET, TokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.AT));
|
||||
private static final TokenSet RESOURCE_EXPRESSIONS = TokenSet.create(
|
||||
JavaElementType.REFERENCE_EXPRESSION, JavaElementType.THIS_EXPRESSION);
|
||||
|
||||
private static final String WHITESPACES = "\n\r \t";
|
||||
private static final String LINE_ENDS = "\n\r";
|
||||
@@ -575,6 +577,16 @@ public class DeclarationParser {
|
||||
|
||||
@Nullable
|
||||
public PsiBuilder.Marker parseResource(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder);
|
||||
if (expr != null && RESOURCE_EXPRESSIONS.contains(exprType(expr)) && builder.getTokenType() != JavaTokenType.IDENTIFIER) {
|
||||
marker.done(JavaElementType.RESOURCE_EXPRESSION);
|
||||
return marker;
|
||||
}
|
||||
|
||||
marker.rollbackTo();
|
||||
|
||||
return parseListElement(builder, true, false, false, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -1163,10 +1163,14 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
public void visitResourceList(final PsiResourceList resourceList) {
|
||||
startElement(resourceList);
|
||||
|
||||
final List<PsiResourceVariable> resources = resourceList.getResourceVariables();
|
||||
for (PsiResourceVariable resource : resources) {
|
||||
for (PsiResourceListElement resource : resourceList) {
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
processVariable(resource);
|
||||
if (resource instanceof PsiResourceVariable) {
|
||||
processVariable((PsiVariable)resource);
|
||||
}
|
||||
else if (resource instanceof PsiResourceExpression) {
|
||||
((PsiResourceExpression)resource).getExpression().accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
finishElement(resourceList);
|
||||
|
||||
@@ -239,11 +239,9 @@ public class PsiImplUtil {
|
||||
final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
|
||||
if (hint != null && !hint.shouldProcess(ElementClassHint.DeclarationKind.VARIABLE)) return true;
|
||||
|
||||
final List<PsiResourceVariable> resources = resourceList.getResourceVariables();
|
||||
@SuppressWarnings({"SuspiciousMethodCalls"})
|
||||
final int lastIdx = lastParent instanceof PsiResourceVariable ? resources.indexOf(lastParent) : resources.size();
|
||||
for (int i = 0; i < lastIdx; i++) {
|
||||
if (!processor.execute(resources.get(i), state)) return false;
|
||||
for (PsiResourceListElement resource : resourceList) {
|
||||
if (resource == lastParent) break;
|
||||
if (resource instanceof PsiResourceVariable && !processor.execute(resource, state)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -133,6 +133,7 @@ public interface JavaElementType {
|
||||
IElementType TRY_STATEMENT = new JavaCompositeElementType("TRY_STATEMENT", PsiTryStatementImpl.class);
|
||||
IElementType RESOURCE_LIST = new JavaCompositeElementType("RESOURCE_LIST", PsiResourceListImpl.class);
|
||||
IElementType RESOURCE_VARIABLE = new JavaCompositeElementType("RESOURCE_VARIABLE", PsiResourceVariableImpl.class);
|
||||
IElementType RESOURCE_EXPRESSION = new JavaCompositeElementType("RESOURCE_EXPRESSION", PsiResourceExpressionImpl.class);
|
||||
IElementType CATCH_SECTION = new JavaCompositeElementType("CATCH_SECTION", PsiCatchSectionImpl.class);
|
||||
IElementType LABELED_STATEMENT = new JavaCompositeElementType("LABELED_STATEMENT", PsiLabeledStatementImpl.class);
|
||||
IElementType ASSERT_STATEMENT = new JavaCompositeElementType("ASSERT_STATEMENT", PsiAssertStatementImpl.class);
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source.tree.java;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.CompositePsiElement;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PsiResourceExpressionImpl extends CompositePsiElement implements PsiResourceExpression {
|
||||
public PsiResourceExpressionImpl() {
|
||||
super(JavaElementType.RESOURCE_EXPRESSION);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiExpression getExpression() {
|
||||
return (PsiExpression)getFirstChild();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiType getType() {
|
||||
return getExpression().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
((JavaElementVisitor)visitor).visitResourceExpression(this);
|
||||
}
|
||||
else {
|
||||
visitor.visitElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiResourceExpression";
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -24,6 +24,7 @@ import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class PsiResourceListImpl extends CompositePsiElement implements PsiResourceList {
|
||||
@@ -35,17 +36,23 @@ public class PsiResourceListImpl extends CompositePsiElement implements PsiResou
|
||||
public int getResourceVariablesCount() {
|
||||
int count = 0;
|
||||
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (child instanceof PsiResourceVariable) ++count;
|
||||
if (child instanceof PsiResourceListElement) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Deprecated
|
||||
@Override
|
||||
public List<PsiResourceVariable> getResourceVariables() {
|
||||
return PsiTreeUtil.getChildrenOfTypeAsList(this, PsiResourceVariable.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<PsiResourceListElement> iterator() {
|
||||
return PsiTreeUtil.childIterator(this, PsiResourceListElement.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
@@ -66,7 +73,7 @@ public class PsiResourceListImpl extends CompositePsiElement implements PsiResou
|
||||
|
||||
@Override
|
||||
public void deleteChildInternal(@NotNull ASTNode child) {
|
||||
if (child.getPsi() instanceof PsiResourceVariable && getResourceVariablesCount() == 1) {
|
||||
if (child.getPsi() instanceof PsiResourceListElement && getResourceVariablesCount() == 1) {
|
||||
getTreeParent().deleteChildInternal(this);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ assignment.to.final.variable=Cannot assign a value to final variable ''{0}''
|
||||
variable.must.be.final=Variable ''{0}'' is accessed from within inner class, needs to be declared final
|
||||
variable.must.be.final.or.effectively.final=Variable ''{0}'' is accessed from within inner class, needs to be final or effectively final
|
||||
lambda.variable.must.be.final=Variable used in lambda expression should be final or effectively final
|
||||
resource.variable.must.be.final=Variable used as a try-with-resources resource should be final or effectively final
|
||||
initializer.must.be.able.to.complete.normally=Initializer must be able to complete normally
|
||||
weaker.privileges={0}; attempting to assign weaker access privileges (''{1}''); was ''{2}''
|
||||
incompatible.return.type=attempting to use incompatible return type
|
||||
@@ -397,4 +398,5 @@ feature.method.references=Method references
|
||||
feature.lambda.expressions=Lambda expressions
|
||||
feature.type.annotations=Type annotations
|
||||
feature.type.receivers=Receiver parameters
|
||||
feature.try.with.resources.refs=Resource references
|
||||
insufficient.language.level={0} are not supported at this language level
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class MyClass {
|
||||
void f() {
|
||||
String response;
|
||||
AutoCloseable resource;
|
||||
try (re<caret>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class MyClass {
|
||||
void f() {
|
||||
String response;
|
||||
AutoCloseable resource;
|
||||
try (resource<caret>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import java.io.*;
|
||||
|
||||
class UnsupportedFeatures {
|
||||
void m() throws Exception {
|
||||
Reader r1 = new FileReader("/dev/null");
|
||||
try (<error descr="Resource references are not supported at this language level">r1</error>; Reader r2 = new FileReader("/dev/null")) { }
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import java.io.IOException;
|
||||
|
||||
class TryWithResources {
|
||||
final AutoCloseable f1 = null;
|
||||
AutoCloseable f2 = null;
|
||||
|
||||
void testFields() throws Exception {
|
||||
try (f1; <error descr="Variable used as a try-with-resources resource should be final or effectively final">f2</error>) { }
|
||||
catch (Exception ignore) { }
|
||||
}
|
||||
|
||||
void testLocalVars() throws Exception {
|
||||
final AutoCloseable r1 = null;
|
||||
AutoCloseable r2 = null;
|
||||
AutoCloseable r3 = null;
|
||||
try (r1; r2; <error descr="Variable used as a try-with-resources resource should be final or effectively final">r3</error>) { }
|
||||
r3 = null;
|
||||
}
|
||||
|
||||
void testType() throws Exception {
|
||||
String s = "";
|
||||
try (<error descr="Incompatible types. Found: 'java.lang.String', required: 'java.lang.AutoCloseable'">s</error>;
|
||||
<error descr="Incompatible types. Found: 'TryWithResources', required: 'java.lang.AutoCloseable'">this</error>) { }
|
||||
}
|
||||
|
||||
void testUnhandled() {
|
||||
class Resource implements AutoCloseable {
|
||||
@Override public void close() throws IOException { }
|
||||
}
|
||||
Resource r = new Resource();
|
||||
try (<error descr="Unhandled exception from auto-closeable resource: java.io.IOException">r</error>) { }
|
||||
}
|
||||
|
||||
void testResolve() throws Exception {
|
||||
try (<error descr="Cannot resolve symbol 'r'">r</error>; AutoCloseable r = null) { }
|
||||
try (AutoCloseable r = null; r) { }
|
||||
}
|
||||
|
||||
void testUnassigned() throws Exception {
|
||||
AutoCloseable r;
|
||||
try (<error descr="Variable 'r' might not have been initialized">r</error>) {
|
||||
System.out.println(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -15,7 +15,6 @@ class C {
|
||||
@interface Anno { String f(Anno this); }
|
||||
|
||||
void m0() {
|
||||
try (Object <error descr="Receivers are not allowed outside of method parameter list">this</error>) { }
|
||||
Runnable r = (C <error descr="Receivers are not allowed outside of method parameter list">C.this</error>) -> { };
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
PsiJavaFile:TryIncomplete18.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiResourceList:(R<T> r)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiResourceVariable:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R<T>
|
||||
PsiJavaCodeReferenceElement:R<T>
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
PsiJavaToken:LT('<')
|
||||
PsiTypeElement:T
|
||||
PsiJavaCodeReferenceElement:T
|
||||
PsiIdentifier:T('T')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiJavaToken:GT('>')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r('r')
|
||||
PsiErrorElement:'=' expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,14 @@
|
||||
PsiJavaFile:TryNormal10.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiResourceList:(this)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiResourceExpression
|
||||
PsiThisExpression:this
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiKeyword:this('this')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,14 @@
|
||||
PsiJavaFile:TryNormal7.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiResourceList:(r)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiResourceExpression
|
||||
PsiReferenceExpression:r
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:r('r')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,15 @@
|
||||
PsiJavaFile:TryNormal8.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiResourceList:(r;)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiResourceExpression
|
||||
PsiReferenceExpression:r
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:r('r')
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,31 @@
|
||||
PsiJavaFile:TryNormal9.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiResourceList:(r1; R r2 = 0)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiResourceExpression
|
||||
PsiReferenceExpression:r1
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:r1('r1')
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiResourceVariable:r2
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
PsiJavaCodeReferenceElement:R
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:r2('r2')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:EQ('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiLiteralExpression:0
|
||||
PsiJavaToken:INTEGER_LITERAL('0')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
+1
@@ -38,6 +38,7 @@ public class Normal17CompletionTest extends LightFixtureCompletionTestCase {
|
||||
public void testOnlyResourcesInResourceList2() { doTest() }
|
||||
public void testOnlyResourcesInResourceList3() { doTest() }
|
||||
public void testOnlyResourcesInResourceList4() { doTest() }
|
||||
public void testOnlyResourcesInResourceList5() { doTest() }
|
||||
|
||||
public void testMethodReferenceNoStatic() { doTest() }
|
||||
public void testMethodReferenceCallContext() { doTest() }
|
||||
|
||||
+1
@@ -48,4 +48,5 @@ public class LightAdvHighlightingJdk8Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testMethodReferences() { doTest(false, true); }
|
||||
public void testUsedMethodsByMethodReferences() { enableInspectionTool(new UnusedDeclarationInspection()); doTest(true, true); }
|
||||
public void testLambdaExpressions() { doTest(false, true); }
|
||||
public void testUnsupportedFeatures() { doTest(false, false); }
|
||||
}
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ public class LightAdvHighlightingJdk9Test extends LightDaemonAnalyzerTestCase {
|
||||
|
||||
public void testSafeVarargsApplicability() { doTest(true, false); }
|
||||
public void testPrivateInInterfaces() { doTest(false, false); }
|
||||
public void testTryWithResources() { doTest(false, false); }
|
||||
|
||||
public void testValueTypes() { setLanguageLevel(LanguageLevel.JDK_X); doTest(false, false); }
|
||||
}
|
||||
|
||||
@@ -122,6 +122,10 @@ public class StatementParserTest extends JavaParsingTestCase {
|
||||
public void testTryNormal4() { doParserTest("try(R r = 0){}"); }
|
||||
public void testTryNormal5() { doParserTest("try(R1 r1 = 1; R2 r2 = 2){}"); }
|
||||
public void testTryNormal6() { doParserTest("try(R r = 0;){}"); }
|
||||
public void testTryNormal7() { doParserTest("try(r){}"); }
|
||||
public void testTryNormal8() { doParserTest("try(r;){}"); }
|
||||
public void testTryNormal9() { doParserTest("try(r1; R r2 = 0){}"); }
|
||||
public void testTryNormal10() { doParserTest("try(this){}"); }
|
||||
public void testTryIncomplete0() { doParserTest("try"); }
|
||||
public void testTryIncomplete1() { doParserTest("try{}"); }
|
||||
public void testTryIncomplete2() { doParserTest("try{}catch"); }
|
||||
@@ -140,6 +144,7 @@ public class StatementParserTest extends JavaParsingTestCase {
|
||||
public void testTryIncomplete15() { doParserTest("try(R r){}"); }
|
||||
public void testTryIncomplete16() { doParserTest("try(R r =){}"); }
|
||||
public void testTryIncomplete17() { doParserTest("try(R r = 0;;){}"); }
|
||||
public void testTryIncomplete18() { doParserTest("try(R<T> r){}"); }
|
||||
|
||||
public void testWhileNormal() { doParserTest("while (true) foo();"); }
|
||||
public void testWhileIncomplete0() { doParserTest("while"); }
|
||||
|
||||
@@ -1044,4 +1044,29 @@ public class PsiTreeUtil {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T extends PsiElement> Iterator<T> childIterator(@NotNull final PsiElement element, @NotNull final Class<T> aClass) {
|
||||
return new Iterator<T>() {
|
||||
private T next = getChildOfType(element, aClass);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (next == null) throw new NoSuchElementException();
|
||||
T current = this.next;
|
||||
next = getNextSiblingOfType(current, aClass);
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user