mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
IDEA-86242 Code completion do not suggest members of known common supertype
This commit is contained in:
@@ -169,9 +169,9 @@ public final class TypeConstraint {
|
||||
if (that.myNotInstanceofValues.containsAll(myNotInstanceofValues) && that.myInstanceofValues.containsAll(myInstanceofValues)) {
|
||||
return true;
|
||||
}
|
||||
if (this.myNotInstanceofValues.isEmpty() && that.myNotInstanceofValues.isEmpty() && this.myInstanceofValues.size() == 1) {
|
||||
DfaPsiType type = this.myInstanceofValues.iterator().next();
|
||||
return that.myInstanceofValues.stream().allMatch(type::isAssignableFrom);
|
||||
if (this.myNotInstanceofValues.isEmpty() && that.myNotInstanceofValues.isEmpty()) {
|
||||
return that.myInstanceofValues.stream().allMatch(
|
||||
thatType -> this.myInstanceofValues.stream().allMatch(thisType -> thisType.isAssignableFrom(thatType)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -180,29 +180,25 @@ public final class TypeConstraint {
|
||||
public TypeConstraint union(@NotNull TypeConstraint other) {
|
||||
if(isSuperStateOf(other)) return this;
|
||||
if(other.isSuperStateOf(this)) return other;
|
||||
Set<DfaPsiType> leftTypes = new HashSet<>(this.myInstanceofValues);
|
||||
Set<DfaPsiType> leftNotTypes = new HashSet<>(this.myNotInstanceofValues);
|
||||
Set<DfaPsiType> rightTypes = new HashSet<>(other.myInstanceofValues);
|
||||
Set<DfaPsiType> rightNotTypes = new HashSet<>(other.myNotInstanceofValues);
|
||||
filter(leftTypes, rightTypes, rightNotTypes);
|
||||
filter(rightTypes, leftTypes, leftNotTypes);
|
||||
TypeConstraint left = create(leftTypes, leftNotTypes);
|
||||
TypeConstraint right = create(rightTypes, rightNotTypes);
|
||||
if(left.isSuperStateOf(right)) return left;
|
||||
if(right.isSuperStateOf(left)) return right;
|
||||
return null;
|
||||
Set<DfaPsiType> notTypes = new HashSet<>(this.myNotInstanceofValues);
|
||||
notTypes.retainAll(other.myNotInstanceofValues);
|
||||
Set<DfaPsiType> instanceOfTypes;
|
||||
if (this.myInstanceofValues.containsAll(other.myInstanceofValues)) {
|
||||
instanceOfTypes = other.myInstanceofValues;
|
||||
} else if (other.myInstanceofValues.containsAll(this.myInstanceofValues)) {
|
||||
instanceOfTypes = this.myInstanceofValues;
|
||||
} else {
|
||||
instanceOfTypes = withSuper(this.myInstanceofValues);
|
||||
instanceOfTypes.retainAll(withSuper(other.myInstanceofValues));
|
||||
}
|
||||
TypeConstraint constraint = StreamEx.of(instanceOfTypes).foldLeft(EMPTY, TypeConstraint::withInstanceofValue);
|
||||
return StreamEx.of(notTypes).foldLeft(constraint, TypeConstraint::withNotInstanceofValue);
|
||||
}
|
||||
|
||||
private static void filter(Set<DfaPsiType> leftTypes, Set<DfaPsiType> rightTypes, Set<DfaPsiType> rightNotTypes) {
|
||||
Set<DfaPsiType> addTypes = new HashSet<>();
|
||||
for (Iterator<DfaPsiType> iterator = leftTypes.iterator(); iterator.hasNext(); ) {
|
||||
DfaPsiType type = iterator.next();
|
||||
if(rightNotTypes.remove(type)) {
|
||||
iterator.remove();
|
||||
StreamEx.of(rightTypes).filter(t -> t.isAssignableFrom(type)).into(addTypes);
|
||||
}
|
||||
}
|
||||
leftTypes.addAll(addTypes);
|
||||
private static Set<DfaPsiType> withSuper(Set<DfaPsiType> instanceofValues) {
|
||||
return StreamEx.of(instanceofValues)
|
||||
.flatMap(type -> StreamEx.of(type.getPsiType().getSuperTypes()).map(type.getFactory()::createDfaType).append(type))
|
||||
.toSet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -20,22 +20,18 @@ import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class DfaPsiType {
|
||||
private final PsiType myPsiType;
|
||||
private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myAssignableCache;
|
||||
private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myConvertibleCache;
|
||||
private final DfaValueFactory myFactory;
|
||||
private final int myID;
|
||||
|
||||
DfaPsiType(int id, @NotNull PsiType psiType, Map<Pair<DfaPsiType, DfaPsiType>, Boolean> assignableCache, Map<Pair<DfaPsiType, DfaPsiType>, Boolean> convertibleCache) {
|
||||
DfaPsiType(int id, @NotNull PsiType psiType, DfaValueFactory factory) {
|
||||
myID = id;
|
||||
myPsiType = psiType;
|
||||
myAssignableCache = assignableCache;
|
||||
myConvertibleCache = convertibleCache;
|
||||
myFactory = factory;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -46,21 +42,17 @@ public class DfaPsiType {
|
||||
public boolean isAssignableFrom(DfaPsiType other) {
|
||||
if (other == this) return true;
|
||||
Pair<DfaPsiType, DfaPsiType> key = Pair.create(this, other);
|
||||
Boolean result = myAssignableCache.get(key);
|
||||
if (result == null) {
|
||||
myAssignableCache.put(key, result = myPsiType.isAssignableFrom(other.myPsiType));
|
||||
}
|
||||
return result;
|
||||
return myFactory.myAssignableCache.computeIfAbsent(key, k -> myPsiType.isAssignableFrom(other.myPsiType));
|
||||
}
|
||||
|
||||
public boolean isConvertibleFrom(DfaPsiType other) {
|
||||
if (other == this) return true;
|
||||
Pair<DfaPsiType, DfaPsiType> key = Pair.create(this, other);
|
||||
Boolean result = myConvertibleCache.get(key);
|
||||
if (result == null) {
|
||||
myConvertibleCache.put(key, result = myPsiType.isConvertibleFrom(other.myPsiType));
|
||||
}
|
||||
return result;
|
||||
return myFactory.myConvertibleCache.computeIfAbsent(key, k -> myPsiType.isConvertibleFrom(other.myPsiType));
|
||||
}
|
||||
|
||||
public DfaValueFactory getFactory() {
|
||||
return myFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,8 +29,8 @@ import static com.intellij.patterns.StandardPatterns.or;
|
||||
|
||||
public class DfaValueFactory {
|
||||
private final List<DfaValue> myValues = ContainerUtil.newArrayList();
|
||||
private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myAssignableCache = ContainerUtil.newHashMap();
|
||||
private final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myConvertibleCache = ContainerUtil.newHashMap();
|
||||
final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myAssignableCache = ContainerUtil.newHashMap();
|
||||
final Map<Pair<DfaPsiType, DfaPsiType>, Boolean> myConvertibleCache = ContainerUtil.newHashMap();
|
||||
private final Map<PsiType, DfaPsiType> myDfaTypes = ContainerUtil.newHashMap();
|
||||
private final boolean myUnknownMembersAreNullable;
|
||||
private final FieldChecker myFieldChecker;
|
||||
@@ -98,7 +98,7 @@ public class DfaValueFactory {
|
||||
psiType = DfaPsiType.normalizeType(psiType);
|
||||
DfaPsiType dfaType = myDfaTypes.get(psiType);
|
||||
if (dfaType == null) {
|
||||
myDfaTypes.put(psiType, dfaType = new DfaPsiType(myDfaTypes.size() + 1, psiType, myAssignableCache, myConvertibleCache));
|
||||
myDfaTypes.put(psiType, dfaType = new DfaPsiType(myDfaTypes.size() + 1, psiType, this));
|
||||
}
|
||||
return dfaType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import java.math.BigInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
class Test {
|
||||
long test(Object obj) {
|
||||
if (obj instanceof Integer || obj instanceof Long) {
|
||||
obj.long<caret>
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import java.math.BigInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
class Test {
|
||||
long test(Object obj) {
|
||||
if (obj instanceof Integer || obj instanceof Long || obj instanceof String) {
|
||||
obj.compa<caret>
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import java.math.BigInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
class Test {
|
||||
long test(Object obj) {
|
||||
if (obj instanceof Integer || obj instanceof Long || obj instanceof String) {
|
||||
((Comparable) obj).compareTo()
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import java.math.BigInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
class Test {
|
||||
long test(Object obj) {
|
||||
if (obj instanceof Integer || obj instanceof Long) {
|
||||
((Number) obj).longValue()
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,8 @@ class NormalCompletionDfaTest extends NormalCompletionTestCase {
|
||||
void testNoUnnecessaryCastRawDfa() { doTest() }
|
||||
void testNoUnnecessaryCastDeepHierarchy() { doTest() }
|
||||
void testInstanceOfAfterFunction() { doTest() }
|
||||
void testInstanceOfDisjunction() { doTest() }
|
||||
void testInstanceOfDisjunction2() { doTest() }
|
||||
void testComplexInstanceOfDfa() {
|
||||
configureByTestName()
|
||||
myFixture.assertPreferredCompletionItems 0, 'methodFromX', 'methodFromX2', 'methodFromY', 'methodFromY2'
|
||||
|
||||
Reference in New Issue
Block a user