mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-52624 Returns from endless loops are not considered 'all execution paths' returning a value
This commit is contained in:
+12
-1
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiConstantEvaluationHelper;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -51,6 +53,12 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
private List<InstructionImpl> myInstructions;
|
||||
|
||||
private Stack<InstructionImpl> myProcessingStack;
|
||||
private PsiConstantEvaluationHelper myConstantEvaluator;
|
||||
|
||||
public ControlFlowBuilder(Project project) {
|
||||
myConstantEvaluator = JavaPsiFacade.getInstance(project).getConstantEvaluationHelper();
|
||||
|
||||
}
|
||||
|
||||
private class ExceptionInfo {
|
||||
GrCatchClause myClause;
|
||||
@@ -485,7 +493,10 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
if (condition != null) {
|
||||
condition.accept(this);
|
||||
}
|
||||
addPendingEdge(whileStatement, myHead); //break
|
||||
final boolean endless = Boolean.TRUE.equals(myConstantEvaluator.computeConstantExpression(condition));
|
||||
if (!endless) {
|
||||
addPendingEdge(whileStatement, myHead); //break
|
||||
}
|
||||
final GrCondition body = whileStatement.getBody();
|
||||
if (body != null) {
|
||||
body.accept(this);
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi
|
||||
|
||||
public Instruction[] getControlFlow() {
|
||||
if (myControlFlow == null) {
|
||||
myControlFlow = new ControlFlowBuilder().buildControlFlow(this, null, null);
|
||||
myControlFlow = new ControlFlowBuilder(getProject()).buildControlFlow(this, null, null);
|
||||
}
|
||||
|
||||
return myControlFlow;
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public abstract class GrBlockImpl extends GroovyPsiElementImpl implements GrCode
|
||||
|
||||
public Instruction[] getControlFlow() {
|
||||
if (myControlFlow == null) {
|
||||
myControlFlow = new ControlFlowBuilder().buildControlFlow(this, null, null);
|
||||
myControlFlow = new ControlFlowBuilder(getProject()).buildControlFlow(this, null, null);
|
||||
}
|
||||
|
||||
return myControlFlow;
|
||||
|
||||
@@ -33,6 +33,7 @@ public class MissingReturnTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testMissingReturnOvertReturnType() throws Throwable {doTest();}
|
||||
public void testMissingReturnFromClosure() throws Throwable {doTest();}
|
||||
public void testReturnsWithoutValue() throws Throwable {doTest();}
|
||||
public void testEndlessLoop() throws Throwable {doTest();}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
myFixture.enableInspections(new MissingReturnInspection());
|
||||
|
||||
+2
-1
@@ -44,6 +44,7 @@ public class ControlFlowTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testTry7() throws Throwable { doTest(); }
|
||||
public void testWhile1() throws Throwable { doTest(); }
|
||||
public void testWhile2() throws Throwable { doTest(); }
|
||||
public void testWhileNonConstant() throws Throwable { doTest(); }
|
||||
public void testIfInstanceofElse() throws Throwable { doTest(); }
|
||||
|
||||
private static String dumpControlFlow(Instruction[] instructions) {
|
||||
@@ -66,7 +67,7 @@ public class ControlFlowTest extends LightCodeInsightFixtureTestCase {
|
||||
final PsiElement start = file.findElementAt(model.hasSelection() ? model.getSelectionStart() : 0);
|
||||
final PsiElement end = file.findElementAt(model.hasSelection() ? model.getSelectionEnd() - 1 : file.getTextLength() - 1);
|
||||
final GrControlFlowOwner owner = PsiTreeUtil.getParentOfType(PsiTreeUtil.findCommonParent(start, end), GrControlFlowOwner.class, false);
|
||||
final Instruction[] instructions = new ControlFlowBuilder().buildControlFlow(owner, null, null);
|
||||
final Instruction[] instructions = new ControlFlowBuilder(getProject()).buildControlFlow(owner, null, null);
|
||||
final String cf = dumpControlFlow(instructions);
|
||||
assertEquals(input.get(1).trim(), cf.trim());
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ while (true) {
|
||||
-----
|
||||
0(1) element: null
|
||||
1(2) WRITE i
|
||||
2(3,7) element: WHILE statement
|
||||
2(3) element: WHILE statement
|
||||
3(4,5) element: IF statement
|
||||
4(7) READ i
|
||||
5(6) READ i
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ while (true) {
|
||||
-----
|
||||
0(1) element: null
|
||||
1(2) WRITE i
|
||||
2(3,7) element: WHILE statement
|
||||
2(3) element: WHILE statement
|
||||
3(4,5) element: IF statement
|
||||
4(2) READ i
|
||||
5(6) READ i
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
i = 0
|
||||
while (condition()) {
|
||||
if (i > 10) break
|
||||
i++
|
||||
}
|
||||
-----
|
||||
0(1) element: null
|
||||
1(2) WRITE i
|
||||
2(3) element: WHILE statement
|
||||
3(4,8) READ condition
|
||||
4(5,6) element: IF statement
|
||||
5(8) READ i
|
||||
6(7) READ i
|
||||
7(2) WRITE i
|
||||
8() element: null
|
||||
@@ -12,9 +12,10 @@ def i = 6
|
||||
println i
|
||||
-----
|
||||
def i = 6
|
||||
i = <caret>testMethod(i)
|
||||
i = testMethod()
|
||||
|
||||
private int testMethod(int i) {
|
||||
private int testMethod() {
|
||||
int i
|
||||
while (true) {
|
||||
println "preved"
|
||||
i = 42
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
def foo() {
|
||||
while (true) {
|
||||
return 239
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user