Don't move overloads from regular Python files back in resolved elements, mark them as low-priority results

This commit is contained in:
Semyon Proshev
2017-05-13 00:17:50 +03:00
committed by Semyon Proshev
parent eccfd264e3
commit c022047f00
5 changed files with 29 additions and 53 deletions
@@ -119,29 +119,27 @@ public class PyCallExpressionHelper {
public static List<PyCallExpression.PyRatedMarkedCallee> multiResolveRatedCallee(@NotNull PyCallExpression call,
@NotNull PyResolveContext resolveContext,
int implicitOffset) {
final LinkedHashMap<PsiElement, PyCallExpression.PyRatedMarkedCallee> result = new LinkedHashMap<>();
final TypeEvalContext context = resolveContext.getTypeEvalContext();
final List<PyCallExpression.PyRatedMarkedCallee> ratedMarkedCallees = new ArrayList<>();
for (QualifiedRatedResolveResult resolveResult : multiResolveCallee(call.getCallee(), resolveContext)) {
final ClarifiedResolveResult clarifiedResolveResult = clarifyResolveResult(resolveResult, resolveContext, call);
if (clarifiedResolveResult == null) continue;
final PyCallExpression.PyRatedMarkedCallee markedCallee =
markResolveResult(clarifiedResolveResult, resolveContext.getTypeEvalContext(), implicitOffset);
final PyCallExpression.PyRatedMarkedCallee markedCallee = markResolveResult(clarifiedResolveResult, context, implicitOffset);
if (markedCallee == null) continue;
// while clarifying resolve results we could get duplicate callables so we have to group them and select result with highest rate
result.put(markedCallee.getElement(),
StreamEx
.of(markedCallee, result.get(markedCallee.getElement()))
.nonNull()
.max(Comparator.comparingInt(PyCallExpression.PyRatedMarkedCallee::getRate))
.orElse(null));
ratedMarkedCallees.add(markedCallee);
}
return StreamEx
.of(forEveryScopeTakeOverloadsOtherwiseImplementations(result.entrySet(), Map.Entry::getKey, resolveContext.getTypeEvalContext()))
.map(Map.Entry::getValue)
.toList();
return forEveryScopeTakeOverloadsOtherwiseImplementations(ratedMarkedCallees, PyCallExpression.PyRatedMarkedCallee::getElement, context)
// while clarifying resolve results we could get duplicate callables so we have to group them and select result with highest rate
.collect(Collectors.groupingBy(markedCallee -> markedCallee.getElement(), LinkedHashMap::new, Collectors.toList()))
.entrySet()
.stream()
.map(entry -> entry.getValue().stream().max(Comparator.comparingInt(PyCallExpression.PyRatedMarkedCallee::getRate)).orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@NotNull
@@ -405,11 +403,13 @@ public class PyCallExpressionHelper {
}
// normal cases
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
final List<QualifiedRatedResolveResult> resolveResults =
PyUtil.filterTopPriorityResults(multiResolveCallee(callee, resolveContext));
final List<QualifiedRatedResolveResult> resolveResults = multiResolveCallee(callee, resolveContext);
final Stream<QualifiedRatedResolveResult> overloadsOtherwiseImplementations =
forEveryScopeTakeOverloadsOtherwiseImplementations(resolveResults, RatedResolveResult::getElement, context);
final List<PyType> members = StreamEx
.of(forEveryScopeTakeOverloadsOtherwiseImplementations(resolveResults, ResolveResult::getElement, context))
.of(PyUtil.filterTopPriorityResults(overloadsOtherwiseImplementations.collect(Collectors.toList())))
.map(ResolveResult::getElement)
.nonNull()
.peek(element -> PyUtil.verboseOnly(() -> PyPsiUtils.assertValid(element)))
@@ -54,14 +54,12 @@ import com.jetbrains.python.psi.stubs.PyFileStub;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.pyi.PyiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.util.*;
import java.util.function.Function;
public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
protected PyType myType;
@@ -183,10 +181,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
}
}
final Function<RatedResolveResult, PsiElement> mapper = RatedResolveResult::getElement;
return PyiUtil.containsOverloads(resultList, mapper, typeEvalContext)
? PyiUtil.moveOverloadsBack(resultList, mapper, typeEvalContext)
: resultList;
return resultList;
}
synchronized (myNameDefinerNegativeCache) {
@@ -440,6 +440,9 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
else if (elt instanceof PyFile) {
rate = RatedResolveResult.RATE_HIGH;
}
else if (!PyiUtil.isInsideStub(elt) && PyiUtil.isOverload(elt, context)) {
rate = RatedResolveResult.RATE_LOW;
}
else {
rate = RatedResolveResult.RATE_NORMAL;
}
@@ -44,13 +44,11 @@ import com.jetbrains.python.psi.resolve.CompletionVariantsProcessor;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.PyResolveProcessor;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.pyi.PyiUtil;
import com.jetbrains.python.toolbox.Maybe;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.jetbrains.python.psi.PyUtil.as;
@@ -561,13 +559,10 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
}
else {
cls.processClassLevelDeclarations(processor);
final Collection<PsiElement> elements = processor.getElements();
result = PyiUtil.containsOverloads(elements, Function.identity(), context)
? PyiUtil.moveOverloadsBack(elements, Function.identity(), context)
: elements;
result = processor.getElements();
}
return ContainerUtil.map(result, element -> new RatedResolveResult(RatedResolveResult.RATE_NORMAL, element));
return ContainerUtil.map(result, element -> new RatedResolveResult(PyReferenceImpl.getRate(element, context), element));
}
private static Key<Set<PyClassType>> CTX_VISITED = Key.create("PyClassType.Visited");
@@ -28,14 +28,13 @@ import com.jetbrains.python.psi.resolve.*;
import com.jetbrains.python.psi.types.PyClassLikeType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
/**
* @author vlan
@@ -126,22 +125,6 @@ public class PyiUtil {
PyKnownDecoratorUtil.getKnownDecorators((PyFunction)element, context).contains(overload);
}
public static <T> boolean containsOverloads(@NotNull Collection<T> elements,
@NotNull Function<? super T, PsiElement> mapper,
@NotNull TypeEvalContext context) {
return ContainerUtil.exists(elements, element -> isOverload(mapper.apply(element), context));
}
@NotNull
public static <T> List<T> moveOverloadsBack(@NotNull Collection<T> elements,
@NotNull Function<? super T, PsiElement> mapper,
@NotNull TypeEvalContext context) {
return StreamEx
.of(elements)
.sorted((e1, e2) -> Boolean.compare(isOverload(mapper.apply(e1), context), isOverload(mapper.apply(e2), context)))
.toList();
}
private static boolean pyButNotPyiFile(@Nullable PsiFile file) {
return file instanceof PyFile && !(file instanceof PyiFile);
}
@@ -190,20 +173,20 @@ public class PyiUtil {
final PyClassLikeType instanceType = classType.toInstance();
final List<? extends RatedResolveResult> resolveResults = instanceType.resolveMember(name, null, AccessDirection.READ,
PyResolveContext.noImplicits(), false);
return takeFirstElement(resolveResults);
return takeTopPriorityElement(resolveResults);
}
}
else if (originalOwner instanceof PyFile) {
return takeFirstElement(((PyFile)originalOwner).multiResolveName(name));
return takeTopPriorityElement(((PyFile)originalOwner).multiResolveName(name));
}
}
return null;
}
@Nullable
private static PsiElement takeFirstElement(@Nullable List<? extends RatedResolveResult> resolveResults) {
private static PsiElement takeTopPriorityElement(@Nullable List<? extends RatedResolveResult> resolveResults) {
if (!ContainerUtil.isEmpty(resolveResults)) {
return resolveResults.get(0).getElement();
return Collections.max(resolveResults, Comparator.comparingInt(RatedResolveResult::getRate)).getElement();
}
return null;
}