mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[groovy] control flow for negated in and instanceof (IDEA-188424)
This commit is contained in:
+3
-17
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 org.jetbrains.plugins.groovy.lang.psi.controlFlow;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -25,9 +11,9 @@ import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.containers.ObjectIntHashMap;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrInExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.formatter.GrControlStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
|
||||
@@ -94,7 +80,7 @@ public class ControlFlowBuilderUtil {
|
||||
}
|
||||
|
||||
public static boolean isInstanceOfBinary(GrBinaryExpression binary) {
|
||||
if (binary.getOperationTokenType() == GroovyTokenTypes.kIN) {
|
||||
if (binary instanceof GrInExpression) {
|
||||
GrExpression left = binary.getLeftOperand();
|
||||
GrExpression right = binary.getRightOperand();
|
||||
if (left instanceof GrReferenceExpression && ((GrReferenceExpression)left).getQualifier() == null &&
|
||||
|
||||
+9
-16
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -30,19 +16,26 @@ import java.util.Set;
|
||||
*/
|
||||
public class ConditionInstruction extends InstructionImpl implements Instruction {
|
||||
|
||||
private final boolean myNegated;
|
||||
private final Set<ConditionInstruction> myDependent;
|
||||
|
||||
public ConditionInstruction(@NotNull PsiElement element, @NotNull Collection<ConditionInstruction> dependent) {
|
||||
public ConditionInstruction(@NotNull PsiElement element, boolean negated, @NotNull Collection<ConditionInstruction> dependent) {
|
||||
super(element);
|
||||
myNegated = negated;
|
||||
myDependent = new LinkedHashSet<>(dependent);
|
||||
myDependent.add(this);
|
||||
}
|
||||
|
||||
public boolean isNegated() {
|
||||
return myNegated;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getElementPresentation() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Condition ").append(getElement());
|
||||
if (myNegated) builder.append(", negated");
|
||||
if (myDependent.size() > 1) {
|
||||
builder.append(", dependent: ");
|
||||
builder.append(StringUtil.join(ContainerUtil.filter(myDependent, d -> d != this), i -> String.valueOf(i.num()), ", "));
|
||||
|
||||
+10
-11
@@ -1,6 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// 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 org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Attachment;
|
||||
@@ -22,6 +20,7 @@ import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GrInExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrCondition;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
|
||||
@@ -442,7 +441,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
}
|
||||
|
||||
FList<ConditionInstruction> conditionsBefore = myConditions;
|
||||
ConditionInstruction cond = registerCondition(expression);
|
||||
ConditionInstruction cond = registerCondition(expression, false);
|
||||
addNodeAndCheckPending(cond);
|
||||
|
||||
operand.accept(this);
|
||||
@@ -500,7 +499,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
@Override
|
||||
public void visitInstanceofExpression(@NotNull GrInstanceOfExpression expression) {
|
||||
expression.getOperand().accept(this);
|
||||
processInstanceOf(expression);
|
||||
processInstanceOf(expression, expression.getNegationToken() != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -562,7 +561,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
|
||||
if (ControlFlowBuilderUtil.isInstanceOfBinary(expression)) {
|
||||
expression.getLeftOperand().accept(this);
|
||||
processInstanceOf(expression);
|
||||
processInstanceOf(expression, ((GrInExpression)expression).getNegationToken() != null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -576,7 +575,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
}
|
||||
|
||||
FList<ConditionInstruction> conditionsBefore = myConditions;
|
||||
ConditionInstruction condition = registerCondition(expression);
|
||||
ConditionInstruction condition = registerCondition(expression, false);
|
||||
addNodeAndCheckPending(condition);
|
||||
|
||||
left.accept(this);
|
||||
@@ -619,9 +618,9 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
right.accept(this);
|
||||
}
|
||||
|
||||
private void processInstanceOf(GrExpression expression) {
|
||||
private void processInstanceOf(GrExpression expression, boolean negated) {
|
||||
FList<ConditionInstruction> conditionsBefore = myConditions;
|
||||
ConditionInstruction cond = registerCondition(expression);
|
||||
ConditionInstruction cond = registerCondition(expression, negated);
|
||||
addNodeAndCheckPending(cond);
|
||||
|
||||
addNode(new InstanceOfInstruction(expression, cond));
|
||||
@@ -718,8 +717,8 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ConditionInstruction registerCondition(@NotNull PsiElement element) {
|
||||
ConditionInstruction condition = new ConditionInstruction(element, myConditions);
|
||||
private ConditionInstruction registerCondition(@NotNull PsiElement element, boolean negated) {
|
||||
ConditionInstruction condition = new ConditionInstruction(element, negated, myConditions);
|
||||
myConditions = myConditions.prepend(condition);
|
||||
return condition;
|
||||
}
|
||||
|
||||
+3
-17
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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 org.jetbrains.plugins.groovy.lang.psi.dataFlow;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
@@ -78,12 +64,12 @@ public class DFAType {
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public void addMixin(@Nullable PsiType mixin, ConditionInstruction instruction) {
|
||||
public void addMixin(@Nullable PsiType mixin, @Nullable ConditionInstruction instruction) {
|
||||
if (mixin == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mixins.add(new Mixin(mixin, instruction, false));
|
||||
mixins.add(new Mixin(mixin, instruction, instruction != null && instruction.isNegated()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-15
@@ -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 org.jetbrains.plugins.groovy.lang.controlFlow
|
||||
|
||||
import com.intellij.openapi.editor.SelectionModel
|
||||
@@ -108,6 +94,8 @@ class ControlFlowTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
void testIfInstanceofElse() { doTest() }
|
||||
|
||||
void testIfNegatedInstanceofElse() { doTest() }
|
||||
|
||||
void testReturnMapFromClosure() { doTest() }
|
||||
|
||||
void testSwitchInTryWithThrows() { doTest() }
|
||||
|
||||
+69
@@ -466,6 +466,15 @@ def bar(oo) {
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testNegatedInstanceOfInferring1() {
|
||||
doTest('''\
|
||||
def bar(oo) {
|
||||
boolean b = oo !instanceof String || oo != null
|
||||
o<caret>o
|
||||
}
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testInstanceOfInferring2() {
|
||||
doTest('''\
|
||||
def bar(oo) {
|
||||
@@ -475,6 +484,15 @@ def bar(oo) {
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testNegatedInstanceOfInferring2() {
|
||||
doTest('''\
|
||||
def bar(oo) {
|
||||
boolean b = oo !instanceof String || o<caret>o != null
|
||||
oo
|
||||
}
|
||||
''', JAVA_LANG_STRING)
|
||||
}
|
||||
|
||||
void testInstanceOfInferring3() {
|
||||
doTest('''\
|
||||
def bar(oo) {
|
||||
@@ -484,6 +502,15 @@ def bar(oo) {
|
||||
''', String.canonicalName)
|
||||
}
|
||||
|
||||
void testNegatedInstanceOfInferring3() {
|
||||
doTest('''\
|
||||
def bar(oo) {
|
||||
boolean b = oo !instanceof String && o<caret>o != null
|
||||
oo
|
||||
}
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testInstanceOfInferring4() {
|
||||
doTest('''\
|
||||
def bar(oo) {
|
||||
@@ -493,6 +520,15 @@ def bar(oo) {
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testNegatedInstanceOfInferring4() {
|
||||
doTest('''\
|
||||
def bar(oo) {
|
||||
boolean b = oo !instanceof String && oo != null
|
||||
o<caret>o
|
||||
}
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testInstanceOfInferring5() {
|
||||
doTest('''\
|
||||
def foo(def oo) {
|
||||
@@ -507,6 +543,20 @@ def foo(def oo) {
|
||||
''', null)
|
||||
}
|
||||
|
||||
void testNegatedInstanceOfInferring5() {
|
||||
doTest('''\
|
||||
def foo(def oo) {
|
||||
if (oo !instanceof String || oo !instanceof CharSequence) {
|
||||
oo
|
||||
}
|
||||
else {
|
||||
o<caret>o
|
||||
}
|
||||
|
||||
}
|
||||
''', JAVA_LANG_STRING)
|
||||
}
|
||||
|
||||
void testInstanceOfInferring6() {
|
||||
doTest('''\
|
||||
def foo(bar) {
|
||||
@@ -516,6 +566,17 @@ def foo(bar) {
|
||||
}''', 'java.lang.Runnable')
|
||||
}
|
||||
|
||||
void testNegatedInstanceOfInferring6() {
|
||||
doTest('''\
|
||||
def foo(bar) {
|
||||
if (!(bar !instanceof String) || bar !instanceof Runnable) {
|
||||
|
||||
} else {
|
||||
ba<caret>r
|
||||
}
|
||||
}''', 'java.lang.Runnable')
|
||||
}
|
||||
|
||||
void testInString() {
|
||||
doTest '''\
|
||||
def foo(ii) {
|
||||
@@ -524,6 +585,14 @@ def foo(ii) {
|
||||
}''', 'java.lang.String'
|
||||
}
|
||||
|
||||
void testNegatedInString() {
|
||||
doTest '''\
|
||||
def foo(ii) {
|
||||
if (ii !in String) {}
|
||||
else print i<caret>i
|
||||
}''', 'java.lang.String'
|
||||
}
|
||||
|
||||
void testIndexProperty() {
|
||||
doTest('''\
|
||||
private void getCommonAncestor() {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
if (o !instanceof String) b = 1
|
||||
else if (!(o !instanceof Integer)) b = 2
|
||||
else b = 3
|
||||
-----
|
||||
0(1) element: null
|
||||
1(2) element: IF statement
|
||||
2(3) READ o
|
||||
3(4,6) Condition Instanceof expression, negated
|
||||
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,15) Condition Instanceof expression, negated, dependent: 10
|
||||
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(21) element: Assignment expression MAYBE_RETURN
|
||||
19(20) WRITE b
|
||||
20(21) element: Assignment expression MAYBE_RETURN
|
||||
21(22) End element: IF statement
|
||||
22(23) End element: IF statement
|
||||
23() element: null
|
||||
Reference in New Issue
Block a user