mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Project Coin try-with-resource support, take 2
This commit is contained in:
@@ -22,6 +22,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -206,10 +207,10 @@ public class ExceptionUtil {
|
||||
PsiClassType exception = getUnhandledException(statement, topElement);
|
||||
unhandledExceptions = exception == null ? Collections.<PsiClassType>emptyList() : Collections.singletonList(exception);
|
||||
}
|
||||
else if (element instanceof PsiCodeBlock
|
||||
&& element.getParent() instanceof PsiMethod
|
||||
&& ((PsiMethod)element.getParent()).isConstructor()
|
||||
&& !firstStatementIsConstructorCall((PsiCodeBlock)element)) {
|
||||
else if (element instanceof PsiCodeBlock &&
|
||||
element.getParent() instanceof PsiMethod &&
|
||||
((PsiMethod)element.getParent()).isConstructor() &&
|
||||
!firstStatementIsConstructorCall((PsiCodeBlock)element)) {
|
||||
// there is implicit parent constructor call
|
||||
final PsiMethod constructor = (PsiMethod)element.getParent();
|
||||
final PsiClass aClass = constructor.getContainingClass();
|
||||
@@ -246,6 +247,22 @@ public class ExceptionUtil {
|
||||
unhandledExceptions = unhandled;
|
||||
}
|
||||
|
||||
if (PsiUtil.isResourceInTryStatement(element)) {
|
||||
final PsiType resourceType = PsiUtil.getResourceType(element);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unhandledExceptions != null) {
|
||||
if (foundExceptions == null) {
|
||||
foundExceptions = new THashSet<PsiClassType>();
|
||||
@@ -309,15 +326,28 @@ public class ExceptionUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiClassType> getUnhandledExceptions(PsiCallExpression methodCall, PsiElement topElement) {
|
||||
public static List<PsiClassType> getUnhandledExceptions(final PsiCallExpression methodCall, final PsiElement topElement) {
|
||||
final JavaResolveResult result = methodCall.resolveMethodGenerics();
|
||||
PsiMethod method = (PsiMethod)result.getElement();
|
||||
return getUnhandledExceptions(method, methodCall, topElement,
|
||||
ApplicationManager.getApplication().runReadAction(new Computable<PsiSubstitutor>() {
|
||||
public PsiSubstitutor compute() {
|
||||
return result.getSubstitutor();
|
||||
}
|
||||
}));
|
||||
final PsiMethod method = (PsiMethod)result.getElement();
|
||||
final PsiSubstitutor substitutor = ApplicationManager.getApplication().runReadAction(new Computable<PsiSubstitutor>() {
|
||||
public PsiSubstitutor compute() {
|
||||
return result.getSubstitutor();
|
||||
}
|
||||
});
|
||||
return getUnhandledExceptions(method, methodCall, topElement, substitutor);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -335,7 +365,6 @@ public class ExceptionUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private static List<PsiClassType> getUnhandledExceptions(PsiMethod method,
|
||||
PsiElement element,
|
||||
|
||||
+25
-8
@@ -553,18 +553,19 @@ public class HighlightUtil {
|
||||
return JavaErrorMessages.message("unhandled.exceptions", exceptionsText.toString(), unhandledExceptions.size());
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkVariableAlreadyDefined(PsiVariable variable) {
|
||||
if (variable instanceof ExternallyDefinedPsiElement) return null;
|
||||
boolean isIncorrect = false;
|
||||
PsiIdentifier identifier = variable.getNameIdentifier();
|
||||
assert identifier != null : variable;
|
||||
String name = variable.getName();
|
||||
if (variable instanceof PsiLocalVariable ||
|
||||
variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiCatchSection ||
|
||||
variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) {
|
||||
variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement ||
|
||||
PsiUtil.isResourceInTryStatement(variable)) {
|
||||
PsiElement scope = PsiTreeUtil.getParentOfType(variable, PsiFile.class, PsiMethod.class, PsiClassInitializer.class);
|
||||
VariablesNotProcessor proc = new VariablesNotProcessor(variable, false){
|
||||
VariablesNotProcessor proc = new VariablesNotProcessor(variable, false) {
|
||||
protected boolean check(final PsiVariable var, final ResolveState state) {
|
||||
return (var instanceof PsiLocalVariable || var instanceof PsiParameter) && super.check(var, state);
|
||||
}
|
||||
@@ -864,13 +865,11 @@ public class HighlightUtil {
|
||||
assert tryBlock != null : statement;
|
||||
thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock));
|
||||
|
||||
final PsiParameterList resources = statement.getResourceList();
|
||||
final PsiResourceList resources = statement.getResourceList();
|
||||
if (resources != null) {
|
||||
thrownTypes.addAll(ExceptionUtil.collectUnhandledExceptions(resources, resources));
|
||||
}
|
||||
|
||||
// todo: add exceptions from resource's close() method
|
||||
|
||||
final PsiType caughtType = parameter.getType();
|
||||
if (caughtType instanceof PsiClassType) {
|
||||
return checkSimpleCatchParameter(parameter, thrownTypes, (PsiClassType)caughtType);
|
||||
@@ -1110,14 +1109,32 @@ public class HighlightUtil {
|
||||
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkCatchParameterIsThrowable(PsiParameter parameter) {
|
||||
public static HighlightInfo checkCatchParameterIsThrowable(final PsiParameter parameter) {
|
||||
if (parameter.getDeclarationScope() instanceof PsiCatchSection) {
|
||||
PsiType type = parameter.getType();
|
||||
final PsiType type = parameter.getType();
|
||||
return checkMustBeThrowable(type, parameter, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull final PsiElement resource) {
|
||||
final PsiType type = PsiUtil.getResourceType(resource);
|
||||
if (type == null) return null;
|
||||
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(resource.getProject()).getElementFactory();
|
||||
final PsiClassType autoCloseable = factory.createTypeByFQClassName("java.lang.AutoCloseable", resource.getResolveScope());
|
||||
if (TypeConversionUtil.isAssignable(autoCloseable, type)) return null;
|
||||
|
||||
final HighlightInfo highlightInfo = createIncompatibleTypeHighlightInfo(autoCloseable, type, resource.getTextRange());
|
||||
//if (addCastIntention && TypeConversionUtil.areTypesConvertible(type, autoCloseable)) {
|
||||
// if (parameter instanceof PsiExpression) {
|
||||
// QuickFixAction.registerQuickFixAction(highlightInfo, new AddTypeCastFix(autoCloseable, (PsiExpression)parameter));
|
||||
// }
|
||||
//}
|
||||
return highlightInfo;
|
||||
}
|
||||
|
||||
public static void checkArrayInitalizer(final PsiExpression initializer, final HighlightInfoHolder holder) {
|
||||
if (! (initializer instanceof PsiArrayInitializerExpression)) return;
|
||||
|
||||
|
||||
+8
-2
@@ -897,12 +897,18 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
@Override public void visitTryStatement(PsiTryStatement statement) {
|
||||
super.visitTryStatement(statement);
|
||||
if (!myHolder.hasErrorResults()) {
|
||||
PsiParameter[] parameters = statement.getCatchBlockParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
for (PsiParameter parameter : statement.getCatchBlockParameters()) {
|
||||
myHolder.addAll(HighlightUtil.checkExceptionThrownInTry(parameter));
|
||||
myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter));
|
||||
myHolder.add(GenericsHighlightUtil.checkCatchParameterIsClass(parameter));
|
||||
}
|
||||
|
||||
PsiResourceList resources = statement.getResourceList();
|
||||
if (resources != null) {
|
||||
for (PsiElement resource : resources.getResources()) {
|
||||
myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import static com.intellij.lang.java.parser.JavaParserUtil.*;
|
||||
|
||||
public class DeclarationParser {
|
||||
public enum Context {
|
||||
FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE
|
||||
FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE, RESOURCE_LIST
|
||||
}
|
||||
|
||||
private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD);
|
||||
@@ -222,7 +222,7 @@ public class DeclarationParser {
|
||||
if (tokenType == null) return null;
|
||||
|
||||
if (tokenType == JavaTokenType.LBRACE) {
|
||||
if (context == Context.FILE || context == Context.CODE_BLOCK) return null;
|
||||
if (context == Context.FILE || context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) return null;
|
||||
}
|
||||
else if (tokenType == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) {
|
||||
if (context == Context.FILE) return null;
|
||||
@@ -234,7 +234,7 @@ public class DeclarationParser {
|
||||
else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) &&
|
||||
!ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) &&
|
||||
tokenType != JavaTokenType.AT &&
|
||||
(context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) {
|
||||
(context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST || tokenType != JavaTokenType.LT)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ public class DeclarationParser {
|
||||
final PsiBuilder.Marker idPos = builder.mark();
|
||||
type = parseTypeNotNull(builder);
|
||||
if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor
|
||||
if (context == Context.CODE_BLOCK) {
|
||||
if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) {
|
||||
declaration.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
@@ -301,6 +301,10 @@ public class DeclarationParser {
|
||||
declaration.drop();
|
||||
return modList;
|
||||
}
|
||||
else if (context == Context.RESOURCE_LIST) {
|
||||
declaration.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker codeBlock = StatementParser.parseCodeBlock(builder);
|
||||
assert codeBlock != null : builder.getOriginalText();
|
||||
@@ -326,7 +330,7 @@ public class DeclarationParser {
|
||||
}
|
||||
|
||||
if (!expect(builder, JavaTokenType.IDENTIFIER)) {
|
||||
if (context == Context.CODE_BLOCK && modListInfo.second) {
|
||||
if ((context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) && modListInfo.second) {
|
||||
declaration.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
@@ -447,33 +451,33 @@ public class DeclarationParser {
|
||||
|
||||
@NotNull
|
||||
public static PsiBuilder.Marker parseParameterList(final PsiBuilder builder) {
|
||||
return parseParameterList(builder, false);
|
||||
return parseElementList(builder, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiBuilder.Marker parseResourceList(final PsiBuilder builder) {
|
||||
return parseParameterList(builder, true);
|
||||
return parseElementList(builder, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiBuilder.Marker parseParameterList(final PsiBuilder builder, final boolean resources) {
|
||||
private static PsiBuilder.Marker parseElementList(final PsiBuilder builder, final boolean resources) {
|
||||
assert builder.getTokenType() == JavaTokenType.LPARENTH : builder.getTokenType();
|
||||
final PsiBuilder.Marker paramList = builder.mark();
|
||||
final PsiBuilder.Marker elementList = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
final IElementType delimiter = resources ? JavaTokenType.SEMICOLON : JavaTokenType.COMMA;
|
||||
final String noDelimiterMsg = JavaErrorMessages.message(resources ? "expected.semicolon" : "expected.comma");
|
||||
final String noParameterMsg = JavaErrorMessages.message(resources ? "expected.resource" : "expected.parameter");
|
||||
final String noElementMsg = JavaErrorMessages.message(resources ? "expected.resource" : "expected.parameter");
|
||||
|
||||
PsiBuilder.Marker invalidElements = null;
|
||||
String errorMessage = null;
|
||||
boolean delimiterExpected = false;
|
||||
int paramCount = 0;
|
||||
int elementCount = 0;
|
||||
while (true) {
|
||||
final IElementType tokenType = builder.getTokenType();
|
||||
if (tokenType == null || tokenType == JavaTokenType.RPARENTH || tokenType == JavaTokenType.LBRACE) {
|
||||
boolean noLastParam = !delimiterExpected && paramCount > 0;
|
||||
if (noLastParam) {
|
||||
boolean noLastElement = !delimiterExpected && elementCount > 0;
|
||||
if (noLastElement) {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier.or.type"));
|
||||
}
|
||||
if (tokenType == JavaTokenType.RPARENTH) {
|
||||
@@ -481,13 +485,13 @@ public class DeclarationParser {
|
||||
invalidElements.error(errorMessage);
|
||||
invalidElements = null;
|
||||
}
|
||||
else if (resources && paramCount == 0) {
|
||||
else if (resources && elementCount == 0) {
|
||||
error(builder, JavaErrorMessages.message("expected.resource"));
|
||||
}
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
if (!noLastParam) {
|
||||
if (!noLastElement) {
|
||||
if (invalidElements != null) {
|
||||
invalidElements.error(errorMessage);
|
||||
}
|
||||
@@ -510,27 +514,27 @@ public class DeclarationParser {
|
||||
}
|
||||
}
|
||||
else {
|
||||
final PsiBuilder.Marker param = parseParameter(builder, true, false, resources);
|
||||
if (param != null) {
|
||||
final PsiBuilder.Marker listElement = resources ? parseResource(builder) : parseParameter(builder, true, false);
|
||||
if (listElement != null) {
|
||||
delimiterExpected = true;
|
||||
if (invalidElements != null) {
|
||||
invalidElements.errorBefore(errorMessage, param);
|
||||
invalidElements.errorBefore(errorMessage, listElement);
|
||||
invalidElements = null;
|
||||
}
|
||||
paramCount++;
|
||||
elementCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidElements == null) {
|
||||
if (builder.getTokenType() == delimiter) {
|
||||
error(builder, noParameterMsg);
|
||||
error(builder, noElementMsg);
|
||||
builder.advanceLexer();
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
invalidElements = builder.mark();
|
||||
errorMessage = delimiterExpected ? noDelimiterMsg : noParameterMsg;
|
||||
errorMessage = delimiterExpected ? noDelimiterMsg : noElementMsg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,19 +549,19 @@ public class DeclarationParser {
|
||||
invalidElements.error(errorMessage);
|
||||
}
|
||||
|
||||
done(paramList, JavaElementType.PARAMETER_LIST);
|
||||
return paramList;
|
||||
done(elementList, resources ? JavaElementType.RESOURCE_LIST : JavaElementType.PARAMETER_LIST);
|
||||
return elementList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunction, final boolean value) {
|
||||
public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunctiveType) {
|
||||
final PsiBuilder.Marker param = builder.mark();
|
||||
|
||||
final Pair<PsiBuilder.Marker, Boolean> modListInfo = parseModifierList(builder);
|
||||
|
||||
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD;
|
||||
if (ellipsis) flags |= ReferenceParser.ELLIPSIS;
|
||||
if (disjunction) flags |= ReferenceParser.DISJUNCTIONS;
|
||||
if (disjunctiveType) flags |= ReferenceParser.DISJUNCTIONS;
|
||||
final ReferenceParser.TypeInfo typeInfo = ReferenceParser.parseTypeInfo(builder, flags);
|
||||
|
||||
if (typeInfo == null) {
|
||||
@@ -572,23 +576,24 @@ public class DeclarationParser {
|
||||
}
|
||||
|
||||
if (expect(builder, JavaTokenType.IDENTIFIER)) {
|
||||
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg || value, JavaErrorMessages.message("expected.rparen"));
|
||||
if (value) {
|
||||
if (expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"))) {
|
||||
if (ExpressionParser.parse(builder) == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.expression"));
|
||||
}
|
||||
}
|
||||
}
|
||||
eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen"));
|
||||
done(param, JavaElementType.PARAMETER);
|
||||
return param;
|
||||
}
|
||||
else {
|
||||
error(builder, JavaErrorMessages.message("expected.identifier"));
|
||||
param.drop();
|
||||
return modListInfo.first;
|
||||
}
|
||||
}
|
||||
|
||||
done(param, JavaElementType.PARAMETER);
|
||||
return param;
|
||||
@Nullable
|
||||
private static PsiBuilder.Marker parseResource(final PsiBuilder builder) {
|
||||
PsiBuilder.Marker resource = parse(builder, Context.RESOURCE_LIST);
|
||||
if (resource == null) {
|
||||
resource = ExpressionParser.parse(builder);
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -598,7 +603,7 @@ public class DeclarationParser {
|
||||
if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) {
|
||||
varType = JavaElementType.FIELD;
|
||||
}
|
||||
else if (context == Context.CODE_BLOCK) {
|
||||
else if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) {
|
||||
varType = JavaElementType.LOCAL_VARIABLE;
|
||||
}
|
||||
else {
|
||||
@@ -629,6 +634,11 @@ public class DeclarationParser {
|
||||
unclosed = true;
|
||||
break;
|
||||
}
|
||||
if (context == Context.RESOURCE_LIST) break;
|
||||
}
|
||||
else if (context == Context.RESOURCE_LIST) {
|
||||
error(builder, JavaErrorMessages.message("expected.eq"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (builder.getTokenType() != JavaTokenType.COMMA) break;
|
||||
@@ -647,26 +657,28 @@ public class DeclarationParser {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
|
||||
if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
// special treatment (see DeclarationParserTest.testMultiLineUnclosed())
|
||||
if (!builder.eof() && shouldRollback) {
|
||||
final CharSequence text = builder.getOriginalText();
|
||||
final int spaceEnd = builder.getCurrentOffset();
|
||||
final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES);
|
||||
final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS);
|
||||
|
||||
if (declarationStart < lineStart && lineStart < spaceStart) {
|
||||
final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES);
|
||||
declaration.rollbackTo();
|
||||
return parse(stoppingBuilder(builder, newBufferEnd), context);
|
||||
}
|
||||
if (context != Context.RESOURCE_LIST) {
|
||||
if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
// special treatment (see DeclarationParserTest.testMultiLineUnclosed())
|
||||
if (!builder.eof() && shouldRollback) {
|
||||
final CharSequence text = builder.getOriginalText();
|
||||
final int spaceEnd = builder.getCurrentOffset();
|
||||
final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES);
|
||||
final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS);
|
||||
|
||||
if (!unclosed) {
|
||||
error(builder, JavaErrorMessages.message("expected.semicolon"));
|
||||
if (declarationStart < lineStart && lineStart < spaceStart) {
|
||||
final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES);
|
||||
declaration.rollbackTo();
|
||||
return parse(stoppingBuilder(builder, newBufferEnd), context);
|
||||
}
|
||||
}
|
||||
|
||||
if (!unclosed) {
|
||||
error(builder, JavaErrorMessages.message("expected.semicolon"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,7 +375,7 @@ public class StatementParser {
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker afterParenth = builder.mark();
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, false, false);
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, false);
|
||||
if (param == null || JavaParserUtil.exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) {
|
||||
afterParenth.rollbackTo();
|
||||
return parseForLoopFromInitialization(builder, statement);
|
||||
@@ -657,7 +657,7 @@ public class StatementParser {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, areMultiCatchSupported(builder), false);
|
||||
final PsiBuilder.Marker param = DeclarationParser.parseParameter(builder, false, areMultiCatchSupported(builder));
|
||||
if (param == null) {
|
||||
error(builder, JavaErrorMessages.message("expected.parameter"));
|
||||
}
|
||||
|
||||
@@ -268,7 +268,6 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// generate jump to the top finally block
|
||||
if (!myFinallyBlocks.isEmpty()) {
|
||||
final PsiElement finallyBlock = myFinallyBlocks.peek();
|
||||
@@ -278,13 +277,10 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
addElementOffsetLater(finallyBlock, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void generateCheckedExceptionJumps(PsiElement element) {
|
||||
//generate jumps to all handled exception handlers
|
||||
//if (myCatchBlocks.size() != 0) {
|
||||
//}
|
||||
Collection<PsiClassType> unhandledExceptions = ExceptionUtil.collectUnhandledExceptions(element, element.getParent());
|
||||
for (PsiClassType unhandledException : unhandledExceptions) {
|
||||
ProgressManager.checkCanceled();
|
||||
@@ -1040,6 +1036,11 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor {
|
||||
generateCheckedExceptionJumps(tryBlock);
|
||||
tryBlock.accept(this);
|
||||
}
|
||||
PsiResourceList resourceList = statement.getResourceList();
|
||||
if (resourceList != null) {
|
||||
generateCheckedExceptionJumps(resourceList);
|
||||
resourceList.accept(this);
|
||||
}
|
||||
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (myUnhandledExceptionCatchBlocks.pop() != null) ;
|
||||
|
||||
@@ -185,8 +185,10 @@ public class PsiImplUtil {
|
||||
if (list != null && !list.processDeclarations(processor, state, null, place)) return false;
|
||||
}
|
||||
if (lastParent instanceof PsiCodeBlock) {
|
||||
final PsiParameterList parameterList = method.getParameterList();
|
||||
if (processDeclarationsInParameterList(parameterList, processor, state)) return false;
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!processor.execute(parameter, state)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -196,24 +198,17 @@ public class PsiImplUtil {
|
||||
@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state,
|
||||
final PsiElement lastParent) {
|
||||
if (lastParent instanceof PsiCodeBlock) {
|
||||
final PsiParameterList parameterList = statement.getResourceList();
|
||||
if (parameterList != null && processDeclarationsInParameterList(parameterList, processor, state)) return false;
|
||||
final PsiResourceList resourceList = statement.getResourceList();
|
||||
if (resourceList != null && lastParent instanceof PsiCodeBlock && lastParent == statement.getTryBlock()) {
|
||||
final List<PsiLocalVariable> resources = resourceList.getNamedResources();
|
||||
for (PsiLocalVariable resource : resources) {
|
||||
if (!processor.execute(resource, state)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean processDeclarationsInParameterList(@NotNull final PsiParameterList parameterList,
|
||||
@NotNull final PsiScopeProcessor processor,
|
||||
@NotNull final ResolveState state) {
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!processor.execute(parameter, state)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasTypeParameters(@NotNull PsiTypeParameterListOwner owner) {
|
||||
final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
|
||||
return typeParameterList != null && typeParameterList.getTypeParameters().length != 0;
|
||||
|
||||
@@ -60,14 +60,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
|
||||
private static final JavaParserUtil.ParserWrapper PARAMETER = new JavaParserUtil.ParserWrapper() {
|
||||
@Override
|
||||
public void parse(final PsiBuilder builder) {
|
||||
DeclarationParser.parseParameter(builder, true, false, false);
|
||||
}
|
||||
};
|
||||
|
||||
private static final JavaParserUtil.ParserWrapper RESOURCE = new JavaParserUtil.ParserWrapper() {
|
||||
@Override
|
||||
public void parse(final PsiBuilder builder) {
|
||||
DeclarationParser.parseParameter(builder, true, false, true);
|
||||
DeclarationParser.parseParameter(builder, true, false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -239,10 +232,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ
|
||||
|
||||
@NotNull
|
||||
public PsiParameter createParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException {
|
||||
final boolean resource = context instanceof PsiParameterList &&
|
||||
context.getParent() instanceof PsiTryStatement;
|
||||
final JavaParserUtil.ParserWrapper wrapper = resource ? RESOURCE : PARAMETER;
|
||||
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, wrapper, false), context);
|
||||
final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, PARAMETER, false), context);
|
||||
final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode());
|
||||
if (!(element instanceof PsiParameter)) {
|
||||
throw new IncorrectOperationException("Incorrect parameter \"" + text + "\".");
|
||||
|
||||
@@ -127,9 +127,10 @@ public interface JavaElementType {
|
||||
IElementType THROW_STATEMENT = new JavaCompositeElementType("THROW_STATEMENT", PsiThrowStatementImpl.class);
|
||||
IElementType SYNCHRONIZED_STATEMENT = new JavaCompositeElementType("SYNCHRONIZED_STATEMENT", PsiSynchronizedStatementImpl.class);
|
||||
IElementType TRY_STATEMENT = new JavaCompositeElementType("TRY_STATEMENT", PsiTryStatementImpl.class);
|
||||
IElementType RESOURCE_LIST = new JavaCompositeElementType("RESOURCE_LIST", PsiResourceListImpl.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);
|
||||
IElementType CATCH_SECTION = new JavaCompositeElementType("CATCH_SECTION", PsiCatchSectionImpl.class);
|
||||
IElementType ANNOTATION_ARRAY_INITIALIZER = new JavaCompositeElementType("ANNOTATION_ARRAY_INITIALIZER", PsiArrayInitializerMemberValueImpl.class);
|
||||
IElementType NAME_VALUE_PAIR = new JavaCompositeElementType("NAME_VALUE_PAIR", PsiNameValuePairImpl.class, true);
|
||||
IElementType ANNOTATION_PARAMETER_LIST = new JavaCompositeElementType("ANNOTATION_PARAMETER_LIST", PsiAnnotationParameterListImpl.class, true);
|
||||
|
||||
+10
-3
@@ -94,7 +94,7 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca
|
||||
@NotNull
|
||||
public PsiTypeElement getTypeElement() {
|
||||
ASTNode first = getTreeParent().findChildByType(LOCAL_VARIABLE);
|
||||
return (PsiTypeElement)SourceTreeToPsiMap.treeElementToPsi(first.findChildByType(TYPE));
|
||||
return SourceTreeToPsiMap.treeToPsiNotNull(first.findChildByType(TYPE));
|
||||
}
|
||||
|
||||
public PsiModifierList getModifierList() {
|
||||
@@ -105,7 +105,8 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca
|
||||
}
|
||||
|
||||
public boolean hasModifierProperty(@NotNull String name) {
|
||||
return getModifierList().hasModifierProperty(name);
|
||||
final PsiModifierList modifierList = getModifierList();
|
||||
return modifierList != null && modifierList.hasModifierProperty(name);
|
||||
}
|
||||
|
||||
public PsiExpression getInitializer() {
|
||||
@@ -304,10 +305,15 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca
|
||||
}
|
||||
}
|
||||
|
||||
PsiElement parentElement = getParent();
|
||||
final PsiElement parentElement = getParent();
|
||||
if (parentElement instanceof PsiDeclarationStatement) {
|
||||
return new LocalSearchScope(parentElement.getParent());
|
||||
}
|
||||
else if (parentElement instanceof PsiResourceList) {
|
||||
final PsiElement tryStatement = parentElement.getParent();
|
||||
final PsiCodeBlock tryBlock = ((PsiTryStatement)tryStatement).getTryBlock();
|
||||
return new LocalSearchScope(tryBlock != null ? tryBlock : tryStatement);
|
||||
}
|
||||
else {
|
||||
return getManager().getFileManager().getUseScope(this);
|
||||
}
|
||||
@@ -317,6 +323,7 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLoca
|
||||
final RowIcon baseIcon = createLayeredIcon(Icons.VARIABLE_ICON, ElementPresentationUtil.getFlags(this, false));
|
||||
return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon);
|
||||
}
|
||||
|
||||
public PsiType getTypeNoResolve() {
|
||||
return getType();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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 com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PsiResourceListImpl extends CompositePsiElement implements PsiResourceList {
|
||||
public PsiResourceListImpl() {
|
||||
super(JavaElementType.RESOURCE_LIST);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends PsiElement> getResources() {
|
||||
//noinspection unchecked
|
||||
return PsiTreeUtil.getChildrenOfAnyType(this, PsiExpression.class, PsiLocalVariable.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<PsiLocalVariable> getNamedResources() {
|
||||
return PsiTreeUtil.getChildrenOfTypeAsList(this, PsiLocalVariable.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull final PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
((JavaElementVisitor)visitor).visitResourceList(this);
|
||||
}
|
||||
else {
|
||||
visitor.visitElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiResourceList:" + getText();
|
||||
}
|
||||
}
|
||||
@@ -93,8 +93,8 @@ public class PsiTryStatementImpl extends CompositePsiElement implements PsiTrySt
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiParameterList getResourceList() {
|
||||
return PsiTreeUtil.findChildOfType(this, PsiParameterList.class);
|
||||
public PsiResourceList getResourceList() {
|
||||
return PsiTreeUtil.findChildOfType(this, PsiResourceList.class);
|
||||
}
|
||||
|
||||
public ASTNode findChildByRole(int role) {
|
||||
|
||||
+36
-22
@@ -1,31 +1,45 @@
|
||||
import java.io.*;
|
||||
import java.lang.Exception;
|
||||
|
||||
class C {
|
||||
void m0() throws Exception {
|
||||
try (FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
reader.read();
|
||||
} catch (Exception e) {
|
||||
<error descr="Cannot resolve symbol 'reader'">reader</error> = null;
|
||||
}
|
||||
<error descr="Cannot resolve symbol 'reader'">reader</error> = null;
|
||||
static class E extends Exception { }
|
||||
static class E1 extends E { }
|
||||
static class E2 extends E { }
|
||||
static class E3 extends E { }
|
||||
|
||||
static class MyResource implements AutoCloseable {
|
||||
public MyResource() throws E1 { }
|
||||
public void doSomething() throws E2 { }
|
||||
@Override public void close() throws E3 { }
|
||||
}
|
||||
|
||||
void m1() {
|
||||
try (final FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
reader.read();
|
||||
}
|
||||
catch (IOException ignore) { }
|
||||
try (MyResource r = new MyResource()) { r.doSomething(); }
|
||||
catch (E1 | E2 | E3 ignore) { }
|
||||
|
||||
try (final FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
System.out.println("Try.");
|
||||
}
|
||||
catch (IOException ignore) { }
|
||||
try (new MyResource()) { }
|
||||
catch (E1 | E3 ignore) { }
|
||||
}
|
||||
|
||||
/*void m2() throws IOException {
|
||||
try (final FileReader reader = new FileReader(new File("input.txt"))) {
|
||||
reader.read();
|
||||
void m2() throws Exception {
|
||||
try (<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.AutoCloseable'">Object r = new MyResource()</error>) { }
|
||||
|
||||
try (<error descr="Incompatible types. Found: 'java.lang.String', required: 'java.lang.AutoCloseable'">"resource"</error>) { }
|
||||
}
|
||||
|
||||
void m3() throws Exception {
|
||||
try (MyResource r = new MyResource()) {
|
||||
r.doSomething();
|
||||
}
|
||||
}*/
|
||||
catch (E e) {
|
||||
<error descr="Cannot resolve symbol 'r'">r</error> = null;
|
||||
}
|
||||
finally {
|
||||
<error descr="Cannot resolve symbol 'r'">r</error> = null;
|
||||
}
|
||||
<error descr="Cannot resolve symbol 'r'">r</error> = null;
|
||||
|
||||
MyResource r = null;
|
||||
|
||||
try (MyResource <error descr="Variable 'r' is already defined in the scope">r</error> = new MyResource()) { }
|
||||
|
||||
try (r = new MyResource()) { }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
PsiJavaFile:TryIncomplete10.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(
|
||||
PsiResourceList:(
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiErrorElement:')' expected
|
||||
<empty list>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PsiJavaFile:TryIncomplete11.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:()
|
||||
PsiResourceList:()
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiErrorElement:Resource definition expected
|
||||
<empty list>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PsiJavaFile:TryIncomplete12.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(;)
|
||||
PsiResourceList:(;)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiErrorElement:Resource definition expected
|
||||
<empty list>
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
PsiJavaFile:TryIncomplete13.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(final )
|
||||
PsiResourceList:(final )
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiModifierList:final
|
||||
PsiKeyword:final('final')
|
||||
PsiErrorElement:Type expected
|
||||
PsiErrorElement:Identifier or type expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeElement:
|
||||
<empty list>
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -1,18 +1,11 @@
|
||||
PsiJavaFile:TryIncomplete14.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R)
|
||||
PsiResourceList:(int)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
PsiJavaCodeReferenceElement:R
|
||||
PsiIdentifier:R('R')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiErrorElement:Identifier expected
|
||||
<empty list>
|
||||
PsiErrorElement:Resource definition expected
|
||||
PsiKeyword:int('int')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -1,9 +1,9 @@
|
||||
PsiJavaFile:TryIncomplete15.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r)
|
||||
PsiResourceList:(R r)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiLocalVariable:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
PsiJavaFile:TryIncomplete16.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r =)
|
||||
PsiResourceList:(R r =)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiLocalVariable:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
PsiJavaFile:TryIncomplete17.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r = 0;)
|
||||
PsiResourceList:(R r = 0;)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiLocalVariable:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
PsiJavaFile:TryNormal4.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R r = 0)
|
||||
PsiResourceList:(R r = 0)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r
|
||||
PsiLocalVariable:r
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
PsiJavaFile:TryNormal5.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiParameterList:(R1 r1 = 1; R2 r2 = 2)
|
||||
PsiResourceList:(R1 r1 = 1; R2 r2 = 2)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiParameter:r1
|
||||
PsiLocalVariable:r1
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R1
|
||||
@@ -20,7 +20,7 @@ PsiJavaFile:TryNormal5.java
|
||||
PsiJavaToken:INTEGER_LITERAL('1')
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiParameter:r2
|
||||
PsiLocalVariable:r2
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:R2
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
PsiJavaFile:TryNormal6.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiResourceList:(r)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiReferenceExpression:r
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:r('r')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,17 @@
|
||||
PsiJavaFile:TryNormal7.java
|
||||
PsiTryStatement
|
||||
PsiKeyword:try('try')
|
||||
PsiResourceList:(r; null)
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiReferenceExpression:r
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiIdentifier:r('r')
|
||||
PsiJavaToken:SEMICOLON(';')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiLiteralExpression:null
|
||||
PsiJavaToken:NULL_KEYWORD('null')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiCodeBlock
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
+3
-1
@@ -122,6 +122,8 @@ public class StatementParserTest extends JavaParsingTestCase {
|
||||
public void testTryNormal3() { doParserTestJDK7("try{}catch(A|B e){}"); }
|
||||
public void testTryNormal4() { doParserTestJDK7("try(R r = 0){}"); }
|
||||
public void testTryNormal5() { doParserTestJDK7("try(R1 r1 = 1; R2 r2 = 2){}"); }
|
||||
public void testTryNormal6() { doParserTestJDK7("try(r){}"); }
|
||||
public void testTryNormal7() { doParserTestJDK7("try(r; null){}"); }
|
||||
public void testTryIncomplete0() { doParserTest("try"); }
|
||||
public void testTryIncomplete1() { doParserTest("try{}"); }
|
||||
public void testTryIncomplete2() { doParserTest("try{}catch"); }
|
||||
@@ -136,7 +138,7 @@ public class StatementParserTest extends JavaParsingTestCase {
|
||||
public void testTryIncomplete11() { doParserTestJDK7("try(){}"); }
|
||||
public void testTryIncomplete12() { doParserTestJDK7("try(;){}"); }
|
||||
public void testTryIncomplete13() { doParserTestJDK7("try(final ){}"); }
|
||||
public void testTryIncomplete14() { doParserTestJDK7("try(R){}"); }
|
||||
public void testTryIncomplete14() { doParserTestJDK7("try(int){}"); }
|
||||
public void testTryIncomplete15() { doParserTestJDK7("try(R r){}"); }
|
||||
public void testTryIncomplete16() { doParserTestJDK7("try(R r =){}"); }
|
||||
public void testTryIncomplete17() { doParserTestJDK7("try(R r = 0;){}"); }
|
||||
|
||||
@@ -238,7 +238,7 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
|
||||
* of this method we can easily stuck with exponential algorithm if the derived visitor
|
||||
* extends visitElement() and accepts children there.
|
||||
* PsiRecursiveElement visitor works that around and implements this method accordingly.
|
||||
* All other visitor must decide themselves what implementation (visitReferenceElement() or visitExpreission() or none or LOG.error())
|
||||
* All other visitor must decide themselves what implementation (visitReferenceElement() or visitExpression() or none or LOG.error())
|
||||
* is appropriate for them.
|
||||
* @param expression
|
||||
*/
|
||||
@@ -296,6 +296,10 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
|
||||
visitElement(section);
|
||||
}
|
||||
|
||||
public void visitResourceList(PsiResourceList resourceList) {
|
||||
visitElement(resourceList);
|
||||
}
|
||||
|
||||
public void visitTypeElement(PsiTypeElement type) {
|
||||
visitElement(type);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a resource list of try-with-resources statement (automatic resource management) introduced in JDK 7.
|
||||
*
|
||||
* @see PsiTryStatement#getResourceList()
|
||||
* @since 10.5.
|
||||
*/
|
||||
public interface PsiResourceList extends PsiElement {
|
||||
/**
|
||||
* Returns list of resource elements. Each element is either {@link PsiLocalVariable} or {@link PsiExpression}.
|
||||
*
|
||||
* @return list of resource elements.
|
||||
*/
|
||||
@NotNull
|
||||
List<? extends PsiElement> getResources();
|
||||
|
||||
/**
|
||||
* Returns list of named resource elements only.
|
||||
*
|
||||
* @return list of named resource elements.
|
||||
*/
|
||||
@NotNull
|
||||
List<PsiLocalVariable> getNamedResources();
|
||||
}
|
||||
@@ -71,5 +71,5 @@ public interface PsiTryStatement extends PsiStatement {
|
||||
* @return resource list, or null if the statement doesn't have it.
|
||||
*/
|
||||
@Nullable
|
||||
PsiParameterList getResourceList();
|
||||
PsiResourceList getResourceList();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.util;
|
||||
|
||||
import com.intellij.openapi.diagnostic.LogUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
@@ -635,6 +636,19 @@ public final class PsiUtil extends PsiUtilBase {
|
||||
return PsiTreeUtil.getParentOfType(element, PsiDocComment.class, true) != null;
|
||||
}
|
||||
|
||||
public static boolean isResourceInTryStatement(final PsiElement element) {
|
||||
return (element instanceof PsiLocalVariable || element instanceof PsiExpression) &&
|
||||
element.getParent() instanceof PsiResourceList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getResourceType(final PsiElement element) {
|
||||
if (element == null || !(element.getParent() instanceof PsiResourceList)) return null;
|
||||
if (element instanceof PsiLocalVariable) return ((PsiLocalVariable)element).getType();
|
||||
if (element instanceof PsiExpression) return ((PsiExpression)element).getType();
|
||||
LOG.error("Unexpected resource type: " + LogUtil.objectAndClass(element));
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ParamWriteProcessor implements Processor<PsiReference> {
|
||||
private volatile boolean myIsWriteRefFound = false;
|
||||
@@ -651,6 +665,7 @@ public final class PsiUtil extends PsiUtilBase {
|
||||
return myIsWriteRefFound;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isAssigned(final PsiParameter parameter) {
|
||||
ParamWriteProcessor processor = new ParamWriteProcessor();
|
||||
ReferencesSearch.search(parameter, new LocalSearchScope(parameter.getDeclarationScope()), true).forEach(processor);
|
||||
@@ -717,7 +732,7 @@ public final class PsiUtil extends PsiUtilBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Returns iterator of type parameters visible in owner. Type parameters are iterated in
|
||||
* inner-to-outer, right-to-left order.
|
||||
*/
|
||||
|
||||
@@ -312,6 +312,22 @@ public class PsiTreeUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<? extends PsiElement> getChildrenOfAnyType(@Nullable final PsiElement element,
|
||||
@Nullable final Class<? extends PsiElement>... classes) {
|
||||
if (element == null || classes == null || classes.length == 0) return Collections.emptyList();
|
||||
|
||||
final List<PsiElement> result = new SmartList<PsiElement>();
|
||||
for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
for (Class<? extends PsiElement> aClass : classes) {
|
||||
if (aClass.isInstance(child)) {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T extends PsiElement> T getNextSiblingOfType(@Nullable PsiElement sibling, @NotNull Class<T> aClass) {
|
||||
if (sibling == null) return null;
|
||||
|
||||
Reference in New Issue
Block a user