mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-08-26 00:11:26 +07:00
ControlFlowAnalyzer: fix control flow for assert (IDEA-186305)
This commit is contained in:
+2
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.controlFlow;
|
||||
|
||||
import com.intellij.psi.PsiExpression;
|
||||
@@ -28,7 +14,7 @@ public class ConditionalGoToInstruction extends ConditionalBranchingInstruction
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@NonNls final String sRole = "["+role.toString()+"]";
|
||||
@NonNls final String sRole = "[" + role + "]";
|
||||
return "COND_GOTO " + sRole + " " + offset;
|
||||
}
|
||||
|
||||
|
||||
+2
-22
@@ -1,30 +1,10 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.controlFlow;
|
||||
|
||||
import com.intellij.psi.PsiExpression;
|
||||
|
||||
public class ConditionalThrowToInstruction extends ConditionalBranchingInstruction {
|
||||
|
||||
public ConditionalThrowToInstruction(int offset, PsiExpression expression) {
|
||||
super(offset, expression, Role.END);
|
||||
}
|
||||
|
||||
public ConditionalThrowToInstruction(final int offset) {
|
||||
this(offset, null);
|
||||
super(offset, null, Role.END);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.controlFlow;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
@@ -928,6 +914,12 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
exception.accept(this);
|
||||
}
|
||||
final List<PsiElement> blocks = findThrowToBlocks(statement);
|
||||
addThrowInstructions(blocks);
|
||||
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
private void addThrowInstructions(@NotNull List<PsiElement> blocks) {
|
||||
PsiElement element;
|
||||
if (blocks.isEmpty() || blocks.get(0) == null) {
|
||||
ThrowToInstruction instruction = new ThrowToInstruction(0);
|
||||
@@ -954,16 +946,13 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
addElementOffsetLater(element, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* find offsets of catch(es) corresponding to this throw statement
|
||||
* myCatchParameters and myCatchBlocks arrays should be sorted in ascending scope order (from outermost to innermost)
|
||||
*
|
||||
* @return offset or -1 if not found
|
||||
* @return list of targets or list of single null element if no appropriate targets found
|
||||
*/
|
||||
@NotNull
|
||||
private List<PsiElement> findThrowToBlocks(@NotNull PsiThrowStatement statement) {
|
||||
@@ -1002,33 +991,49 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
myCurrentFlow.addInstruction(passByWhenAssertionsDisabled);
|
||||
addElementOffsetLater(statement, false);
|
||||
|
||||
// should not try to compute constant expression within assert
|
||||
// since assertions can be disabled/enabled at any moment via JVM flags
|
||||
|
||||
final PsiExpression condition = statement.getAssertCondition();
|
||||
if (condition != null) {
|
||||
myStartStatementStack.pushStatement(statement, false);
|
||||
myEndStatementStack.pushStatement(statement, false);
|
||||
|
||||
myEndJumpRoles.push(BranchingInstruction.Role.END);
|
||||
myStartJumpRoles.push(BranchingInstruction.Role.END);
|
||||
|
||||
condition.accept(this);
|
||||
|
||||
myStartJumpRoles.pop();
|
||||
myEndJumpRoles.pop();
|
||||
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
}
|
||||
PsiExpression description = statement.getAssertDescription();
|
||||
if (description != null) {
|
||||
description.accept(this);
|
||||
boolean generateCondition = true;
|
||||
boolean generateThrow = true;
|
||||
if (myEvaluateConstantIfCondition) {
|
||||
Object conditionValue = myConstantEvaluationHelper.computeConstantExpression(condition);
|
||||
if (conditionValue instanceof Boolean) {
|
||||
generateThrow = !((Boolean)conditionValue);
|
||||
generateCondition = false;
|
||||
emitEmptyInstruction();
|
||||
}
|
||||
}
|
||||
|
||||
Instruction instruction = new ConditionalThrowToInstruction(0, statement.getAssertCondition());
|
||||
myCurrentFlow.addInstruction(instruction);
|
||||
addElementOffsetLater(myCodeFragment, false);
|
||||
if (generateCondition) {
|
||||
if (condition != null) {
|
||||
myStartStatementStack.pushStatement(statement, false);
|
||||
myEndStatementStack.pushStatement(statement, false);
|
||||
|
||||
myEndJumpRoles.push(BranchingInstruction.Role.END);
|
||||
myStartJumpRoles.push(BranchingInstruction.Role.END);
|
||||
|
||||
condition.accept(this);
|
||||
|
||||
myStartJumpRoles.pop();
|
||||
myEndJumpRoles.pop();
|
||||
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
}
|
||||
Instruction ifTrue = new ConditionalGoToInstruction(0, BranchingInstruction.Role.END, statement.getAssertCondition());
|
||||
myCurrentFlow.addInstruction(ifTrue);
|
||||
addElementOffsetLater(statement, false);
|
||||
}
|
||||
if (generateThrow) {
|
||||
PsiExpression description = statement.getAssertDescription();
|
||||
if (description != null) {
|
||||
description.accept(this);
|
||||
}
|
||||
// if description is evaluated, the assert statement cannot complete normally
|
||||
// though non-necessarily AssertionError will be thrown (description may throw something, or AssertionError ctor, etc.)
|
||||
PsiClassType exceptionClass = JavaPsiFacade.getElementFactory(statement.getProject()).createTypeByFQClassName(
|
||||
CommonClassNames.JAVA_LANG_THROWABLE, statement.getResolveScope());
|
||||
addThrowInstructions(findThrowToBlocks(exceptionClass));
|
||||
}
|
||||
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
|
||||
+19
@@ -92,4 +92,23 @@ class T1 {
|
||||
(i4) = 1;
|
||||
(<error descr="Expression expected">)</error>++;
|
||||
}
|
||||
}
|
||||
class T3 {
|
||||
private final boolean b;
|
||||
{
|
||||
assert false : "" + (b = true); // if assignment reachable, assert will not complete normally
|
||||
b = true; // compiles
|
||||
System.out.println(b);
|
||||
}
|
||||
}
|
||||
class T3a {
|
||||
private final boolean b;
|
||||
{
|
||||
try {
|
||||
assert false : "" + (b = true);
|
||||
}
|
||||
catch(IllegalArgumentException t) {}
|
||||
<error descr="Variable 'b' might already have been assigned to">b</error> = true; // red
|
||||
System.out.println(b);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user