mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
type inference
This commit is contained in:
+44
@@ -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();
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -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<? extends NegatingGotoInstruction> getNegatingGotoInstruction();
|
||||
|
||||
@Nullable
|
||||
PsiElement getElement();
|
||||
|
||||
+3
-12
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+149
-80
@@ -88,11 +88,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
private Deque<ConditionInstruction> myConditions;
|
||||
|
||||
|
||||
/**
|
||||
* stack of negating instructions
|
||||
*/
|
||||
private Deque<NegatingGotoInstruction> myNegatingStack;
|
||||
|
||||
/**
|
||||
* count of finally blocks surrounding current statement
|
||||
*/
|
||||
@@ -159,7 +154,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
myProcessingStack = new ArrayDeque<InstructionImpl>();
|
||||
myCaughtExceptionInfos = new ArrayDeque<ExceptionInfo>();
|
||||
myConditions = new ArrayDeque<ConditionInstruction>();
|
||||
myNegatingStack = new ArrayDeque<NegatingGotoInstruction>();
|
||||
|
||||
myFinallyCount = 0;
|
||||
myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>();
|
||||
@@ -222,7 +216,6 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
|
||||
private <T extends InstructionImpl> 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<GotoInstruction> negations = collectAndRemoveAllPendingNegations(expression);
|
||||
|
||||
addPendingEdge(expression, addNodeAndCheckPending(new PositiveGotoInstruction(expression, myInstructionNumber++, cond)));
|
||||
|
||||
myHead = reduceAllNegationsIntoInstruction(expression, negations);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private InstructionImpl reduceAllNegationsIntoInstruction(GroovyPsiElement currentScope, List<? extends GotoInstruction> 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<GotoInstruction> collectAndRemoveAllPendingNegations(GroovyPsiElement currentScope) {
|
||||
List<GotoInstruction> negations = new ArrayList<GotoInstruction>();
|
||||
for (Iterator<Pair<InstructionImpl, GroovyPsiElement>> iterator = myPending.iterator(); iterator.hasNext(); ) {
|
||||
Pair<InstructionImpl, GroovyPsiElement> 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<GotoInstruction> 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<NegatingGotoInstruction> pendingNegations = new ArrayList<NegatingGotoInstruction>();
|
||||
ConditionInstruction conditionStart = null;
|
||||
if (condition != null) {
|
||||
final List<Pair<InstructionImpl, GroovyPsiElement>> oldPending = myPending;
|
||||
myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>();
|
||||
|
||||
conditionStart = addNodeAndCheckPending(new ConditionInstruction(condition, myInstructionNumber++));
|
||||
registerCondition(conditionStart);
|
||||
condition.accept(this);
|
||||
conditionEnd = myHead;
|
||||
|
||||
List<Pair<InstructionImpl, GroovyPsiElement>> pendingFromCondition = myPending;
|
||||
myPending = oldPending;
|
||||
for (Pair<InstructionImpl, GroovyPsiElement> pair : pendingFromCondition) {
|
||||
if (pair.first instanceof NegatingGotoInstruction) {
|
||||
pendingNegations.add((NegatingGotoInstruction)pair.first);
|
||||
}
|
||||
else {
|
||||
addPendingEdge(pair.second, pair.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<GotoInstruction> 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<GotoInstruction> 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<GotoInstruction> 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) {
|
||||
|
||||
+12
-5
@@ -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<InstructionImpl> myPredecessors = new LinkedHashSet<InstructionImpl>();
|
||||
private final LinkedHashSet<InstructionImpl> mySuccessors = new LinkedHashSet<InstructionImpl>();
|
||||
private final LinkedHashSet<NegatingGotoInstruction> myNegations = new LinkedHashSet<NegatingGotoInstruction>();
|
||||
|
||||
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<? extends NegatingGotoInstruction> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ConditionInstruction> conditionsToNegate = negating.getCondition().getDependentConditions();
|
||||
for (NegatingGotoInstruction negation: instruction.getNegatingGotoInstruction()) {
|
||||
final Set<ConditionInstruction> conditionsToNegate = negation.getCondition().getDependentConditions();
|
||||
|
||||
for (ListIterator<Mixin> iterator = type.mixins.listIterator(); iterator.hasNext(); ) {
|
||||
Mixin mixin = iterator.next();
|
||||
|
||||
+5
-3
@@ -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) {
|
||||
|
||||
@@ -528,6 +528,15 @@ def foo(def oo) {
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testInstanceOfInferring6() {
|
||||
doTest('''\
|
||||
def foo(bar) {
|
||||
if (!(bar instanceof String) && bar instanceof Runnable) {
|
||||
ba<caret>r
|
||||
}
|
||||
}''', '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
|
||||
|
||||
+11
-13
@@ -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
|
||||
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
|
||||
+7
-9
@@ -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
|
||||
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
|
||||
@@ -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
|
||||
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
|
||||
+7
-9
@@ -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
|
||||
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
|
||||
+7
-9
@@ -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
|
||||
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
|
||||
+15
-17
@@ -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
|
||||
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
|
||||
+7
-9
@@ -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
|
||||
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
|
||||
+15
-17
@@ -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
|
||||
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
|
||||
+12
-14
@@ -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
|
||||
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
|
||||
+5
-7
@@ -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
|
||||
4(5,8) READ i
|
||||
5(6) element: IF statement
|
||||
6(7) READ i
|
||||
7(2) WRITE i
|
||||
8() element: null
|
||||
+5
-7
@@ -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
|
||||
4(2,5) READ i
|
||||
5(6) element: IF statement
|
||||
6(7) READ i
|
||||
7(2) WRITE j
|
||||
8() element: null
|
||||
@@ -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
|
||||
5(6,9) READ i
|
||||
6(7) element: IF statement
|
||||
7(8) READ i
|
||||
8(2) WRITE i
|
||||
9() element: null
|
||||
Reference in New Issue
Block a user