From 53283e232241d7ab99f5dbd03253fdda58cf475d Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Wed, 17 Oct 2012 15:26:19 +0400 Subject: [PATCH] IDEA-92833 Type inference doesn't update type after assert instanceof --- .../com/intellij/psi/CommonClassNames.java | 1 + .../ipp/asserttoif/IfStatementPredicate.java | 2 +- .../controlFlow/impl/ControlFlowBuilder.java | 25 ++++++-- .../lang/controlFlow/ControlFlowTest.groovy | 64 ++++++++++--------- .../lang/resolve/TypeInferenceTest.groovy | 9 +++ .../testdata/groovy/controlFlow/assert0.test | 14 ++++ .../testdata/groovy/controlFlow/assert1.test | 25 ++++++++ 7 files changed, 101 insertions(+), 39 deletions(-) create mode 100644 plugins/groovy/testdata/groovy/controlFlow/assert0.test create mode 100644 plugins/groovy/testdata/groovy/controlFlow/assert1.test diff --git a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java b/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java index 16b51cc9fa61..50d680fe8e5d 100644 --- a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java +++ b/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java @@ -89,4 +89,5 @@ public interface CommonClassNames { String TARGET_ANNOTATION_FQ_NAME = "java.lang.annotation.Target"; @NonNls String JAVA_LANG_RUNNABLE = "java.lang.Runnable"; @NonNls String JAVA_IO_FILE = "java.io.File"; + String JAVA_LANG_ASSERTION_ERROR = "java.lang.AssertionError"; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/IfStatementPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/IfStatementPredicate.java index aa86dace15fb..2a904a5b2a66 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/IfStatementPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/IfStatementPredicate.java @@ -61,7 +61,7 @@ class IfStatementPredicate implements PsiElementPredicate { } final PsiClass aClass = (PsiClass)target; final String qualifiedName = aClass.getQualifiedName(); - return "java.lang.AssertionError".equals(qualifiedName); + return CommonClassNames.JAVA_LANG_ASSERTION_ERROR.equals(qualifiedName); } else if (element instanceof PsiBlockStatement) { final PsiBlockStatement blockStatement = diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index c368b4094d36..b281c2a82088 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -378,25 +378,34 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { } public void visitAssertStatement(GrAssertStatement assertStatement) { + final InstructionImpl assertInstruction = startNode(assertStatement); + final GrExpression assertion = assertStatement.getAssertion(); if (assertion != null) { - myConditions.push(addNodeAndCheckPending(new ConditionInstruction(assertion))); assertion.accept(this); - final InstructionImpl assertInstruction = startNode(assertStatement); + + InstructionImpl positiveHead = myHead; + interruptFlow(); + + List negations = collectAndRemoveAllPendingNegations(assertStatement); + reduceAllNegationsIntoInstruction(assertStatement, negations); + GrExpression errorMessage = assertStatement.getErrorMessage(); if (errorMessage != null) { errorMessage.accept(this); } - final PsiType type = TypesUtil.createTypeByFQClassName("java.lang.AssertionError", assertStatement); + final PsiType type = TypesUtil.createTypeByFQClassName(CommonClassNames.JAVA_LANG_ASSERTION_ERROR, assertStatement); ExceptionInfo info = findCatch(type); if (info != null) { - info.myThrowers.add(assertInstruction); + info.myThrowers.add(myHead); } else { - addPendingEdge(null, assertInstruction); + addPendingEdge(null, myHead); } - finishNode(assertInstruction); + + myHead = positiveHead; } + finishNode(assertInstruction); } public void visitThrowStatement(GrThrowStatement throwStatement) { @@ -525,7 +534,9 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { return instruction; } else if (negations.size() == 1) { - return negations.get(0); + GotoInstruction instruction = negations.get(0); + myHead = instruction; + return instruction; } return null; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy index 6a01df4ac5ce..634def671721 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy @@ -17,37 +17,37 @@ import org.jetbrains.plugins.groovy.util.TestUtils public class ControlFlowTest extends LightCodeInsightFixtureTestCase { final String basePath = TestUtils.testDataPath + "groovy/controlFlow/" - public void testAssignment() throws Throwable { doTest(); } - public void testClosure1() throws Throwable { doTest(); } - public void testComplexAssign() throws Throwable { doTest(); } - public void testFor1() throws Throwable { doTest(); } - public void testForeach1() throws Throwable { doTest(); } - public void testGrvy1497() throws Throwable { doTest(); } - public void testIf1() throws Throwable { doTest(); } - public void testMultipleAssignment() throws Throwable { doTest(); } - public void testNested() throws Throwable { doTest(); } - public void testReturn() throws Throwable { doTest(); } - public void testSwitch1() throws Throwable { doTest(); } - public void testSwitch2() throws Throwable { doTest(); } - public void testSwitch3() throws Throwable { doTest(); } - public void testSwitch4() throws Throwable { doTest(); } - public void testSwitch5() throws Throwable { doTest(); } - public void testThrow1() throws Throwable { doTest(); } - public void testThrowInCatch() throws Throwable { doTest(); } - public void testTry1() throws Throwable { doTest(); } - public void testTry2() throws Throwable { doTest(); } - public void testTry3() throws Throwable { doTest(); } - public void testTry4() throws Throwable { doTest(); } - public void testTry5() throws Throwable { doTest(); } - public void testTry6() throws Throwable { doTest(); } - public void testTry7() throws Throwable { doTest(); } - public void testTry8() throws Throwable { doTest(); } - public void testTry9() throws Throwable { doTest(); } - public void testTry10() 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(); } + public void testAssignment() { doTest(); } + public void testClosure1() { doTest(); } + public void testComplexAssign() { doTest(); } + public void testFor1() { doTest(); } + public void testForeach1() { doTest(); } + public void testGrvy1497() { doTest(); } + public void testIf1() { doTest(); } + public void testMultipleAssignment() { doTest(); } + public void testNested() { doTest(); } + public void testReturn() { doTest(); } + public void testSwitch1() { doTest(); } + public void testSwitch2() { doTest(); } + public void testSwitch3() { doTest(); } + public void testSwitch4() { doTest(); } + public void testSwitch5() { doTest(); } + public void testThrow1() { doTest(); } + public void testThrowInCatch() { doTest(); } + public void testTry1() { doTest(); } + public void testTry2() { doTest(); } + public void testTry3() { doTest(); } + public void testTry4() { doTest(); } + public void testTry5() { doTest(); } + public void testTry6() { doTest(); } + public void testTry7() { doTest(); } + public void testTry8() { doTest(); } + public void testTry9() { doTest(); } + public void testTry10() { doTest(); } + public void testWhile1() { doTest(); } + public void testWhile2() { doTest(); } + public void testWhileNonConstant() { doTest(); } + public void testIfInstanceofElse() { doTest(); } public void testReturnMapFromClosure() {doTest();} public void testSwitchInTryWithThrows() {doTest();} public void testClosure() {doTest();} @@ -56,6 +56,8 @@ public class ControlFlowTest extends LightCodeInsightFixtureTestCase { public void testOrInReturn() {doTest();} public void testVarInString() {doTest();} public void testMayBeStaticWithCondition() {doTest()} + public void testAssert0() { doTest() } + public void testAssert1() { doTest() } public void doTest() { final List input = TestUtils.readInput(testDataPath + getTestName(true) + ".test"); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy index 3e337f53a3dc..73dd4fdd2dfa 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy @@ -568,6 +568,15 @@ def method(List t) { ''', 'Tx') } + void testAssert() { + doTest('''\ +def foo(def var) { + assert var instanceof String + var.isEmpty() +} +''', 'java.lang.String') + } + private void doTest(String text, String type) { def file = myFixture.configureByText('_.groovy', text) def ref = file.findReferenceAt(myFixture.editor.caretModel.offset) as GrReferenceExpression diff --git a/plugins/groovy/testdata/groovy/controlFlow/assert0.test b/plugins/groovy/testdata/groovy/controlFlow/assert0.test new file mode 100644 index 000000000000..84acf05162cd --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/assert0.test @@ -0,0 +1,14 @@ +assert x instanceof String : bar() +return x.isEmpty() +----- +0(1) element: null +1(2) element: ASSERT statement +2(3) READ x +3(4,6) Condition Instanceof expression +4(5) instanceof: x instanceof String +5(7) Negating goto instruction, condition=3Instanceof expression +6(8) instanceof: x instanceof String +7(10) READ bar +8(9) READ x +9(10) element: RETURN statement +10() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/assert1.test b/plugins/groovy/testdata/groovy/controlFlow/assert1.test new file mode 100644 index 000000000000..56a9b23234e7 --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/assert1.test @@ -0,0 +1,25 @@ +try { + assert x instanceof String : bar() +} +catch (java.lang.AssertionError e) { + return true +} + +return x.isEmpty() +----- +0(1) element: null +1(2) element: Open block +2(3) element: ASSERT statement +3(4) READ x +4(5,7) Condition Instanceof expression +5(6) instanceof: x instanceof String +6(8) Negating goto instruction, condition=4Instanceof expression +7(13) instanceof: x instanceof String +8(9) READ bar +9(10) THROW. element: Method call +10(11) element: Catch clause +11(12) WRITE e +12(15) element: RETURN statement +13(14) READ x +14(15) element: RETURN statement +15() element: null