diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/GotoInstruction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/GotoInstruction.java new file mode 100644 index 000000000000..7a566976feee --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/GotoInstruction.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2012 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 org.jetbrains.plugins.groovy.lang.psi.controlFlow; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ConditionInstruction; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl; + +/** + * @author Max Medvedev + */ +public abstract class GotoInstruction extends InstructionImpl { + @NotNull private final ConditionInstruction myCondition; + + public GotoInstruction(@Nullable PsiElement element, int num, @NotNull ConditionInstruction condition) { + super(element, num); + myCondition = condition; + } + + @NotNull + public ConditionInstruction getCondition() { + return myCondition; + } + + @Override + protected String getElementPresentation() { + return " Positive goto instruction, condition=" + myCondition.num() + getElement(); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java index 83d18548353a..26383bd4a164 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/Instruction.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.psi.controlFlow; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -30,8 +31,8 @@ public interface Instruction { int num(); - @Nullable - NegatingGotoInstruction getNegatingGotoInstruction(); + @NotNull + Iterable getNegatingGotoInstruction(); @Nullable PsiElement getElement(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java index 8aa5955ee609..de949ae5e294 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/NegatingGotoInstruction.java @@ -19,26 +19,17 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ConditionInstruction; -import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl; /** * @author Max Medvedev */ -public class NegatingGotoInstruction extends InstructionImpl { - @NotNull private final ConditionInstruction myCondition; - +public class NegatingGotoInstruction extends GotoInstruction { public NegatingGotoInstruction(@Nullable PsiElement element, int num, @NotNull ConditionInstruction condition) { - super(element, num); - myCondition = condition; - } - - @NotNull - public ConditionInstruction getCondition() { - return myCondition; + super(element, num, condition); } @Override protected String getElementPresentation() { - return " Negating goto instruction, condition=" + myCondition.num() + getElement(); + return " Negating goto instruction, condition=" + getCondition().num() + getElement(); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/PositiveGotoInstruction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/PositiveGotoInstruction.java new file mode 100644 index 000000000000..d0d0c8140980 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/PositiveGotoInstruction.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2012 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 org.jetbrains.plugins.groovy.lang.psi.controlFlow; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ConditionInstruction; + +/** + * @author Max Medvedev + */ +public class PositiveGotoInstruction extends GotoInstruction { + public PositiveGotoInstruction(@Nullable PsiElement element, int num, @NotNull ConditionInstruction condition) { + super(element, num, condition); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java index 9b32fd97c15d..4dfdf506d20a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ConditionInstruction.java @@ -35,7 +35,7 @@ public class ConditionInstruction extends InstructionImpl implements Instruction @Override protected String getElementPresentation() { - return "Condition" + getElement(); + return "Condition " + getElement(); } void addDependent(ConditionInstruction i) { 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 5724e15ccae4..65818f5b0f27 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 @@ -88,11 +88,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { private Deque myConditions; - /** - * stack of negating instructions - */ - private Deque myNegatingStack; - /** * count of finally blocks surrounding current statement */ @@ -159,7 +154,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { myProcessingStack = new ArrayDeque(); myCaughtExceptionInfos = new ArrayDeque(); myConditions = new ArrayDeque(); - myNegatingStack = new ArrayDeque(); myFinallyCount = 0; myPending = new ArrayList>(); @@ -222,7 +216,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { private T addNode(T instruction) { myInstructions.add(instruction); - instruction.setNegating(myNegatingStack.peek()); if (myHead != null) { addEdge(myHead, instruction); } @@ -239,6 +232,10 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { private static void addEdge(InstructionImpl begin, InstructionImpl end) { begin.addSuccessor(end); end.addPredecessor(begin); + + if (!(begin instanceof ReadWriteVariableInstruction || begin instanceof MixinTypeInstruction)) { + end.addNegationsFrom(begin); + } } public void visitClosure(GrClosableBlock closure) { @@ -398,30 +395,76 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { @Override public void visitUnaryExpression(GrUnaryExpression expression) { final GrExpression operand = expression.getOperand(); - if (operand != null) { - ConditionInstruction cond = null; - if (expression.getOperationTokenType() == mLNOT) { - cond = new ConditionInstruction(expression, myInstructionNumber++); - addNodeAndCheckPending(cond); - registerCondition(cond); - } + if (operand == null) return; + + if (expression.getOperationTokenType() != mLNOT) { operand.accept(this); visitCall(expression); + return; + } - if (cond != null) { - myConditions.removeFirstOccurrence(cond); - myNegatingStack.push(addNodeAndCheckPending(new NegatingGotoInstruction(expression, myInstructionNumber++, cond))); + ConditionInstruction cond = new ConditionInstruction(expression, myInstructionNumber++); + addNodeAndCheckPending(cond); + registerCondition(cond); + + operand.accept(this); + visitCall(expression); + + myConditions.removeFirstOccurrence(cond); + + List negations = collectAndRemoveAllPendingNegations(expression); + + addPendingEdge(expression, addNodeAndCheckPending(new PositiveGotoInstruction(expression, myInstructionNumber++, cond))); + + myHead = reduceAllNegationsIntoInstruction(expression, negations); + } + + @Nullable + private InstructionImpl reduceAllNegationsIntoInstruction(GroovyPsiElement currentScope, List negations) { + if (negations.size() > 1) { + InstructionImpl instruction = addNode(new InstructionImpl(currentScope, myInstructionNumber++)); + for (GotoInstruction negation : negations) { + addEdge(negation, instruction); + } + return instruction; + } + else if (negations.size() == 1) { + return negations.get(0); + } + return null; + } + + private List collectAndRemoveAllPendingNegations(GroovyPsiElement currentScope) { + List negations = new ArrayList(); + for (Iterator> iterator = myPending.iterator(); iterator.hasNext(); ) { + Pair pair = iterator.next(); + InstructionImpl instruction = pair.first; + GroovyPsiElement scope = pair.second; + + if (!PsiTreeUtil.isAncestor(scope, currentScope, true) && instruction instanceof GotoInstruction) { + negations.add((GotoInstruction)instruction); + iterator.remove(); } } + return negations; } @Override public void visitInstanceofExpression(GrInstanceOfExpression expression) { expression.getOperand().accept(this); - final ConditionInstruction cond = myConditions.peek(); - if (cond != null) { - addNode(new InstanceOfInstruction(myInstructionNumber++, expression, cond)); - } + + ConditionInstruction cond = new ConditionInstruction(expression, myInstructionNumber++); + addNodeAndCheckPending(cond); + registerCondition(cond); + + addNode(new InstanceOfInstruction(myInstructionNumber++, expression, cond)); + NegatingGotoInstruction negation = new NegatingGotoInstruction(expression, myInstructionNumber++, cond); + addNode(negation); + addPendingEdge(expression, negation); + + myHead = cond; + InstanceOfInstruction instruction = addNode(new InstanceOfInstruction(myInstructionNumber++, expression, cond)); + myConditions.removeFirstOccurrence(cond); } public void visitReferenceExpression(GrReferenceExpression refExpr) { @@ -478,41 +521,48 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { final GrExpression right = expression.getRightOperand(); final IElementType opType = expression.getOperationTokenType(); - final ConditionInstruction cond; - if (opType == mLOR || opType == mLAND) { - cond = addNodeAndCheckPending(new ConditionInstruction(expression, myInstructionNumber++)); - registerCondition(cond); - } - else { - cond = null; + if (opType != mLOR && opType != mLAND) { + left.accept(this); + if (right != null) { + right.accept(this); + } + visitCall(expression); + return; } + + ConditionInstruction condition = new ConditionInstruction(expression, myInstructionNumber++); + addNodeAndCheckPending(condition); + registerCondition(condition); + left.accept(this); - if (cond != null) { - myConditions.removeFirstOccurrence(cond); - } + if (right == null) return; - NegatingGotoInstruction first = null; - if (right != null) { - if (cond != null) { - final InstructionImpl head = myHead; - if (opType == mLAND) { - first = addNodeAndCheckPending(new NegatingGotoInstruction(expression, myInstructionNumber++, cond)); - } - addPendingEdge(expression, myHead); - myHead = head; - if (opType == mLOR) { - myNegatingStack.push(addNodeAndCheckPending(new NegatingGotoInstruction(expression, myInstructionNumber++, cond))); - } - } - - right.accept(this); - } + final List negations = collectAndRemoveAllPendingNegations(expression); visitCall(expression); - if (first != null) { - myNegatingStack.push(first); + + if (opType == mLAND) { + for (GotoInstruction negation : negations) { + addPendingEdge(expression, negation); + } + if (negations.isEmpty()) { + InstructionImpl head = myHead; + NegatingGotoInstruction negation = addNode(new NegatingGotoInstruction(expression, myInstructionNumber++, condition)); + addPendingEdge(expression, negation); + myHead = head; + } } + else /*if (opType == mLOR)*/ { + addNodeAndCheckPending(new InstructionImpl(expression, myInstructionNumber++)); //collect all pending edges from left argument + addPendingEdge(expression, myHead); + + myHead = reduceAllNegationsIntoInstruction(expression, negations); + //addNode(new NegatingGotoInstruction(expression, myInstructionNumber++, condition)); + } + myConditions.removeFirstOccurrence(condition); + + right.accept(this); } /** @@ -539,8 +589,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { public void visitIfStatement(GrIfStatement ifStatement) { InstructionImpl ifInstruction = startNode(ifStatement); - final InstructionImpl head = myHead; - final GrCondition condition = ifStatement.getCondition(); final GrStatement thenBranch = ifStatement.getThenBranch(); final GrStatement elseBranch = ifStatement.getElseBranch(); @@ -549,29 +597,13 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { InstructionImpl thenEnd = null; InstructionImpl elseEnd = null; - List pendingNegations = new ArrayList(); - ConditionInstruction conditionStart = null; if (condition != null) { - final List> oldPending = myPending; - myPending = new ArrayList>(); - - conditionStart = addNodeAndCheckPending(new ConditionInstruction(condition, myInstructionNumber++)); - registerCondition(conditionStart); condition.accept(this); conditionEnd = myHead; - - List> pendingFromCondition = myPending; - myPending = oldPending; - for (Pair pair : pendingFromCondition) { - if (pair.first instanceof NegatingGotoInstruction) { - pendingNegations.add((NegatingGotoInstruction)pair.first); - } - else { - addPendingEdge(pair.second, pair.first); - } - } } + List negations = collectAndRemoveAllPendingNegations(ifStatement); + if (thenBranch != null) { thenBranch.accept(this); handlePossibleReturn(thenBranch); @@ -579,30 +611,29 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { interruptFlow(); } - if (condition != null) { + myHead = reduceAllNegationsIntoInstruction(ifStatement, negations); + if (negations.isEmpty() && conditionEnd != null) { myHead = conditionEnd; - myNegatingStack.push(addNode(new NegatingGotoInstruction(condition, myInstructionNumber++, conditionStart))); - } - else { - myHead = head; - } - - for (NegatingGotoInstruction negation : pendingNegations) { - assert condition != null; - addPendingEdge(condition, negation); } if (elseBranch != null) { elseBranch.accept(this); handlePossibleReturn(elseBranch); elseEnd = myHead; + interruptFlow(); } if (thenBranch != null || elseBranch != null) { final InstructionImpl end = new IfEndInstruction(ifStatement, myInstructionNumber++); addNode(end); if (thenEnd != null) addEdge(thenEnd, end); - if (elseEnd != null) addEdge(elseEnd, end); + if (elseEnd != null) { + addEdge(elseEnd, end); + } + else { + addEdge(conditionEnd != null ? conditionEnd : ifInstruction, end); + } } + finishNode(ifInstruction); } @@ -750,6 +781,44 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { finishNode(instruction); } + @Override + public void visitConditionalExpression(GrConditionalExpression expression) { + GrExpression condition = expression.getCondition(); + GrExpression thenBranch = expression.getThenBranch(); + GrExpression elseBranch = expression.getElseBranch(); + + condition.accept(this); + List negations = collectAndRemoveAllPendingNegations(expression); + + if (thenBranch != null) { + thenBranch.accept(this); + handlePossibleReturn(thenBranch); + addPendingEdge(expression, myHead); + } + + if (elseBranch != null) { + myHead = reduceAllNegationsIntoInstruction(expression, negations); + elseBranch.accept(this); + handlePossibleReturn(elseBranch); + } + } + + @Override + public void visitElvisExpression(GrElvisExpression expression) { + GrExpression condition = expression.getCondition(); + GrExpression elseBranch = expression.getElseBranch(); + + condition.accept(this); + List negations = collectAndRemoveAllPendingNegations(expression); + addPendingEdge(expression, myHead); + + if (elseBranch != null) { + myHead = reduceAllNegationsIntoInstruction(expression, negations); + elseBranch.accept(this); + handlePossibleReturn(elseBranch); + } + } + private static boolean containsAllCases(GrSwitchStatement statement) { final GrCaseSection[] sections = statement.getCaseSections(); for (GrCaseSection section : sections) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java index e81218b67a98..57334ee8d734 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.CallEnvironment; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.CallInstruction; @@ -31,10 +32,10 @@ import java.util.LinkedHashSet; public class InstructionImpl implements Instruction { private final LinkedHashSet myPredecessors = new LinkedHashSet(); private final LinkedHashSet mySuccessors = new LinkedHashSet(); + private final LinkedHashSet myNegations = new LinkedHashSet(); PsiElement myPsiElement; private final int myNumber; - private NegatingGotoInstruction myNegating; @Nullable public PsiElement getElement() { @@ -93,9 +94,10 @@ public class InstructionImpl implements Instruction { return myNumber; } + @NotNull @Override - public NegatingGotoInstruction getNegatingGotoInstruction() { - return myNegating; + public Iterable getNegatingGotoInstruction() { + return myNegations; } public void addSuccessor(InstructionImpl instruction) { @@ -106,7 +108,12 @@ public class InstructionImpl implements Instruction { myPredecessors.add(instruction); } - void setNegating(NegatingGotoInstruction negating) { - myNegating = negating; + void addNegationsFrom(Instruction instruction) { + for (NegatingGotoInstruction negation : instruction.getNegatingGotoInstruction()) { + myNegations.add(negation); + } + if (instruction instanceof NegatingGotoInstruction) { + myNegations.add((NegatingGotoInstruction)instruction); + } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAType.java index eebf8bf17ad5..6f041bead9b2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAType.java @@ -19,7 +19,9 @@ import com.intellij.psi.PsiIntersectionType; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiType; import com.intellij.psi.util.TypeConversionUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.NegatingGotoInstruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ConditionInstruction; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; @@ -92,15 +94,15 @@ public class DFAType { return true; } - public DFAType negate(NegatingGotoInstruction negating) { + public DFAType negate(@NotNull Instruction instruction) { final DFAType type = new DFAType(primary); for (Mixin mixin : mixins) { type.mixins.add(mixin); } - for (; negating != null; negating = negating.getNegatingGotoInstruction()) { - final Set conditionsToNegate = negating.getCondition().getDependentConditions(); + for (NegatingGotoInstruction negation: instruction.getNegatingGotoInstruction()) { + final Set conditionsToNegate = negation.getCondition().getDependentConditions(); for (ListIterator iterator = type.mixins.listIterator(); iterator.hasNext(); ) { Mixin mixin = iterator.next(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java index e0ccf7386a24..45d40b89406b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java @@ -34,7 +34,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; -import org.jetbrains.plugins.groovy.lang.psi.controlFlow.*; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.InstanceOfInstruction; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.MixinTypeInstruction; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ArgumentInstruction; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAType; @@ -150,9 +153,8 @@ public class TypeInferenceHelper { for (int defIndex : varDefs.toArray()) { DFAType defType = getDefinitionType(flow[defIndex], flow, scope); - final NegatingGotoInstruction negating = instruction.getNegatingGotoInstruction(); if (defType != null) { - defType = defType.negate(negating); + defType = defType.negate(instruction); } if (defType != null) { 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 7eb620851311..b293ce2b4fea 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 @@ -528,6 +528,15 @@ def foo(def oo) { ''', null) } + void testInstanceOfInferring6() { + doTest('''\ +def foo(bar) { + if (!(bar instanceof String) && bar instanceof Runnable) { + bar + } +}''', 'java.lang.Runnable') + } + 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/grvy1497.test b/plugins/groovy/testdata/groovy/controlFlow/grvy1497.test index fdd11cd0a264..acc55ec03c94 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/grvy1497.test +++ b/plugins/groovy/testdata/groovy/controlFlow/grvy1497.test @@ -5,16 +5,14 @@ println blah ----- 0(1) element: null 1(2) WRITE blah -2(3) element: IF statement -3(4,6) Condition -4(5) READ blah -5(7) WRITE blah -6(7) Negating goto instruction, condition=3 -7(8) element: IF statement -8(9) READ blah -9(10) WRITE blah -10(11) READ println -11(12) READ blah -12(13) ARGUMENT element: Reference expression -13(14) element: Call expression MAYBE_RETURN -14() element: null \ No newline at end of file +2(3,5) element: IF statement +3(4) READ blah +4(5) WRITE blah +5(6) element: IF statement +6(7) READ blah +7(8) WRITE blah +8(9) READ println +9(10) READ blah +10(11) ARGUMENT element: Reference expression +11(12) element: Call expression MAYBE_RETURN +12() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/if1.test b/plugins/groovy/testdata/groovy/controlFlow/if1.test index f5a6183cee3a..6432efeca933 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/if1.test +++ b/plugins/groovy/testdata/groovy/controlFlow/if1.test @@ -5,12 +5,10 @@ if (true) { a = 2 ----- 0(1) element: null -1(2) element: IF statement -2(3,5) Condition -3(4) WRITE a -4(8) element: Assignment expression MAYBE_RETURN -5(6) Negating goto instruction, condition=2 -6(7) WRITE a -7(8) element: Assignment expression MAYBE_RETURN -8(9) element: IF statement -9() element: null \ No newline at end of file +1(2,4) element: IF statement +2(3) WRITE a +3(6) element: Assignment expression MAYBE_RETURN +4(5) WRITE a +5(6) element: Assignment expression MAYBE_RETURN +6(7) element: IF statement +7() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test b/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test index 8a29021c09b1..767599b66614 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test +++ b/plugins/groovy/testdata/groovy/controlFlow/ifInstanceofElse.test @@ -4,23 +4,25 @@ else b = 3 ----- 0(1) element: null 1(2) element: IF statement -2(3) Condition -3(4) READ o -4(5,7) instanceof: o instanceof String -5(6) WRITE b -6(20) element: Assignment expression MAYBE_RETURN -7(8) Negating goto instruction, condition=2 -8(9) element: IF statement -9(10) Condition -10(11) Condition +2(3) READ o +3(4,6) Condition Instanceof expression +4(5) instanceof: o instanceof String +5(9) Negating goto instruction, condition=3Instanceof expression +6(7) instanceof: o instanceof String +7(8) WRITE b +8(22) element: Assignment expression MAYBE_RETURN +9(10) element: IF statement +10(11) Condition Unary expression 11(12) READ o -12(13) instanceof: o instanceof Integer -13(14,16) Negating goto instruction, condition=10 -14(15) WRITE b -15(19) element: Assignment expression MAYBE_RETURN -16(17) Negating goto instruction, condition=9 +12(13,15) Condition Instanceof expression +13(14) instanceof: o instanceof Integer +14(17) Negating goto instruction, condition=12Instanceof expression +15(16) instanceof: o instanceof Integer +16(19) Positive goto instruction, condition=10Unary expression 17(18) WRITE b -18(19) element: Assignment expression MAYBE_RETURN -19(20) element: IF statement -20(21) element: IF statement -21() element: null \ No newline at end of file +18(21) element: Assignment expression MAYBE_RETURN +19(20) WRITE b +20(21) element: Assignment expression MAYBE_RETURN +21(22) element: IF statement +22(23) element: IF statement +23() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/nested.test b/plugins/groovy/testdata/groovy/controlFlow/nested.test index f49ad96807b0..83c08bb98285 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/nested.test +++ b/plugins/groovy/testdata/groovy/controlFlow/nested.test @@ -9,16 +9,14 @@ for (e in [1,2,3,4]) { 0(1) element: null 1(2) element: Labeled statement 2(3) WRITE e -3(4,15) element: For statement +3(4,13) element: For statement 4(5) element: Block statement 5(6) WRITE ee 6(7,3) element: For statement 7(8) element: Block statement -8(9) element: IF statement -9(1,10) Condition -10(11) Negating goto instruction, condition=9 -11(12) element: IF statement -12(13) READ print -13(14) READ e -14(6) READ ee -15() element: null \ No newline at end of file +8(1,9) element: IF statement +9(10) element: IF statement +10(11) READ print +11(12) READ e +12(6) READ ee +13() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/return.test b/plugins/groovy/testdata/groovy/controlFlow/return.test index e720cd515a65..6809d545a74e 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/return.test +++ b/plugins/groovy/testdata/groovy/controlFlow/return.test @@ -1,12 +1,10 @@ if (true) return a else return b ----- 0(1) element: null -1(2) element: IF statement -2(3,5) Condition -3(4) READ a -4(9) element: RETURN statement -5(6) Negating goto instruction, condition=2 -6(7) READ b -7(9) element: RETURN statement -8(9) element: IF statement -9() element: null \ No newline at end of file +1(2,4,6) element: IF statement +2(3) READ a +3(7) element: RETURN statement +4(5) READ b +5(7) element: RETURN statement +6(7) element: IF statement +7() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try1.test b/plugins/groovy/testdata/groovy/controlFlow/try1.test index 42b3e0bacf11..f284f4e9150e 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try1.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try1.test @@ -8,20 +8,18 @@ print e 0(1) element: null 1(2) element: Open block 2(3) element: IF statement -3(4) Condition -4(5,6) READ c -5(9) element: RETURN statement -6(7) Negating goto instruction, condition=3 -7(11) element: IF statement -8(13) element: Finally clause -9(8,10) CALL 8 -10(19) AFTER CALL 9 -11(8,12) CALL 8 -12(15) AFTER CALL 11 -13(14) READ e -14(10,12) RETURN -15(16) READ print -16(17) READ e -17(18) ARGUMENT element: Reference expression -18(19) element: Call expression MAYBE_RETURN -19() element: null \ No newline at end of file +3(4,5) READ c +4(7) element: RETURN statement +5(9) element: IF statement +6(11) element: Finally clause +7(6,8) CALL 6 +8(17) AFTER CALL 7 +9(6,10) CALL 6 +10(13) AFTER CALL 9 +11(12) READ e +12(8,10) RETURN +13(14) READ print +14(15) READ e +15(16) ARGUMENT element: Reference expression +16(17) element: Call expression MAYBE_RETURN +17() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try10.test b/plugins/groovy/testdata/groovy/controlFlow/try10.test index 215c5c8d8a72..0123a89ab4d5 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try10.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try10.test @@ -10,15 +10,13 @@ cde 1(3) element: Open block 2(5) element: Finally clause 3(2,4) CALL 2 -4(13) AFTER CALL 3 +4(11) AFTER CALL 3 5(6) element: For statement 6(7) element: Block statement 7(8) element: IF statement -8(9) Condition -9(10,12) READ abc -10(11) Negating goto instruction, condition=8 -11(5) element: IF statement -12(4) RETURN -13(14) READ cde -14(15) element: Reference expression MAYBE_RETURN -15() element: null \ No newline at end of file +8(9,10) READ abc +9(5) element: IF statement +10(4) RETURN +11(12) READ cde +12(13) element: Reference expression MAYBE_RETURN +13() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try5.test b/plugins/groovy/testdata/groovy/controlFlow/try5.test index d3ec3937c95e..a6a14ee5a77b 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try5.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try5.test @@ -12,20 +12,18 @@ fScript.previewTask(taskName) ----- 0(1) element: null 1(2) element: IF statement -2(3) Condition -3(4,6) READ ddd -4(5) READ fXRec -5(18) element: RETURN statement -6(7) Negating goto instruction, condition=2 -7(8) element: IF statement -8(9) WRITE fScript -9(11) element: Open block -10(13) element: Finally clause -11(10,12) CALL 10 -12(14) AFTER CALL 11 -13(12) RETURN -14(15) READ fScript -15(16) READ taskName -16(17) ARGUMENT element: Reference expression -17(18) element: Method call MAYBE_RETURN -18() element: null \ No newline at end of file +2(3,5) READ ddd +3(4) READ fXRec +4(16) element: RETURN statement +5(6) element: IF statement +6(7) WRITE fScript +7(9) element: Open block +8(11) element: Finally clause +9(8,10) CALL 8 +10(12) AFTER CALL 9 +11(10) RETURN +12(13) READ fScript +13(14) READ taskName +14(15) ARGUMENT element: Reference expression +15(16) element: Method call MAYBE_RETURN +16() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/try6.test b/plugins/groovy/testdata/groovy/controlFlow/try6.test index 94bcb21c160c..173eaa6bc614 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/try6.test +++ b/plugins/groovy/testdata/groovy/controlFlow/try6.test @@ -10,17 +10,15 @@ return url ----- 0(1) element: null 1(2) element: IF statement -2(3) Condition -3(4,11) READ url -4(5) element: Open block -5(13) WRITE url -6(7) element: Catch clause -7(8) WRITE e -8(9) READ e -9(10) ARGUMENT element: Reference expression -10(15) THROW. element: THROW statement -11(12) Negating goto instruction, condition=2 -12(13) element: IF statement -13(14) READ url -14(15) element: RETURN statement -15() element: null \ No newline at end of file +2(3,10) READ url +3(4) element: Open block +4(11) WRITE url +5(6) element: Catch clause +6(7) WRITE e +7(8) READ e +8(9) ARGUMENT element: Reference expression +9(13) THROW. element: THROW statement +10(11) element: IF statement +11(12) READ url +12(13) element: RETURN statement +13() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/while1.test b/plugins/groovy/testdata/groovy/controlFlow/while1.test index 32691ed75860..cd7c29f2b9da 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/while1.test +++ b/plugins/groovy/testdata/groovy/controlFlow/while1.test @@ -8,10 +8,8 @@ while (true) { 1(2) WRITE i 2(3) element: WHILE statement 3(4) element: IF statement -4(5) Condition -5(6,10) READ i -6(7) Negating goto instruction, condition=4 -7(8) element: IF statement -8(9) READ i -9(2) WRITE i -10() element: null \ No newline at end of file +4(5,8) READ i +5(6) element: IF statement +6(7) READ i +7(2) WRITE i +8() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/while2.test b/plugins/groovy/testdata/groovy/controlFlow/while2.test index 1e98fb09882c..15605553beb5 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/while2.test +++ b/plugins/groovy/testdata/groovy/controlFlow/while2.test @@ -8,10 +8,8 @@ while (true) { 1(2) WRITE i 2(3) element: WHILE statement 3(4) element: IF statement -4(5) Condition -5(2,6) READ i -6(7) Negating goto instruction, condition=4 -7(8) element: IF statement -8(9) READ i -9(2) WRITE j -10() element: null \ No newline at end of file +4(2,5) READ i +5(6) element: IF statement +6(7) READ i +7(2) WRITE j +8() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test b/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test index 9ece4b7bdeea..043e4f397ac6 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test +++ b/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test @@ -7,12 +7,10 @@ while (condition()) { 0(1) element: null 1(2) WRITE i 2(3) element: WHILE statement -3(4,11) READ condition +3(4,9) READ condition 4(5) element: IF statement -5(6) Condition -6(7,11) READ i -7(8) Negating goto instruction, condition=5 -8(9) element: IF statement -9(10) READ i -10(2) WRITE i -11() element: null \ No newline at end of file +5(6,9) READ i +6(7) element: IF statement +7(8) READ i +8(2) WRITE i +9() element: null \ No newline at end of file