mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[groovy] dfa: join mixins with least upper bound (IDEA-205853)
This commit is contained in:
+16
-7
@@ -2,6 +2,7 @@
|
||||
package org.jetbrains.plugins.groovy.lang.psi.dataFlow;
|
||||
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.GenericsUtil;
|
||||
import com.intellij.psi.PsiIntersectionType;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiType;
|
||||
@@ -15,6 +16,8 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
@@ -157,17 +160,23 @@ public class DFAType {
|
||||
|
||||
final PsiType primary = TypesUtil.getLeastUpperBoundNullable(t1.primary, t2.primary, manager);
|
||||
final DFAType type = new DFAType(primary);
|
||||
|
||||
for (Mixin mixin1 : t1.mixins) {
|
||||
for (Mixin mixin2 : t2.mixins) {
|
||||
if (mixin1.equals(mixin2) && mixin1.myNegated == mixin2.myNegated) {
|
||||
type.mixins.add(mixin1);
|
||||
}
|
||||
}
|
||||
final PsiType type1 = reduce(t1.mixins);
|
||||
final PsiType type2 = reduce(t2.mixins);
|
||||
if (type1 != null && type2 != null) {
|
||||
type.addMixin(GenericsUtil.getLeastUpperBound(type1, type2, manager), null);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private static PsiType reduce(List<Mixin> mixins) {
|
||||
List<PsiType> types = mixins.stream()
|
||||
.filter(it -> !it.myNegated)
|
||||
.map(it -> it.myType)
|
||||
.collect(toList());
|
||||
return types.isEmpty() ? null : PsiIntersectionType.createIntersection(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + primary + " : " + mixins + "}";
|
||||
|
||||
+2
@@ -104,6 +104,8 @@ class ControlFlowTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
void testIfNegatedInstanceofElse() { doTest() }
|
||||
|
||||
void testIfInstanceofOr() { doTest() }
|
||||
|
||||
void testReturnMapFromClosure() { doTest() }
|
||||
|
||||
void testSwitchInTryWithThrows() { doTest() }
|
||||
|
||||
+13
@@ -558,6 +558,19 @@ def foo(bar) {
|
||||
}''', 'java.lang.Runnable')
|
||||
}
|
||||
|
||||
void 'test instanceof or instanceof'() {
|
||||
doTest '''\
|
||||
class A {}
|
||||
class B extends A {}
|
||||
class C extends A {}
|
||||
def foo(a) {
|
||||
if (a instanceof B || a instanceof C) {
|
||||
<caret>a
|
||||
}
|
||||
}
|
||||
''', 'A'
|
||||
}
|
||||
|
||||
void 'test enum constant'() {
|
||||
doTest('''\
|
||||
import static MyEnum.*
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
if (a instanceof Integer || a instanceof Double) {
|
||||
a
|
||||
}
|
||||
-----
|
||||
0(1) element: null
|
||||
1(2) element: IF statement
|
||||
2(3) Condition Logical expression
|
||||
3(4) READ a
|
||||
4(5,7) Condition Instanceof expression, dependent: 2
|
||||
5(6) instanceof: a instanceof Integer
|
||||
6(9) Negating goto instruction, condition=4Instanceof expression
|
||||
7(8) instanceof: a instanceof Integer
|
||||
8(14) element: Logical expression
|
||||
9(10) READ a
|
||||
10(11,13) Condition Instanceof expression
|
||||
11(12) instanceof: a instanceof Double
|
||||
12(16) Negating goto instruction, condition=10Instanceof expression
|
||||
13(14) instanceof: a instanceof Double
|
||||
14(15) READ a
|
||||
15(16) element: Reference expression MAYBE_RETURN
|
||||
16(17) End element: IF statement
|
||||
17() element: null
|
||||
Reference in New Issue
Block a user