mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
PY-79816 Introduce PyType#getMemberTypes and use it to infer __hash__ type of dataclasses
`getMemberTypes` should be used for members which have no PSI which can be used to resolve to. For example, `__init__` method in dataclasses are sometimes not present in the source code. Yet its parameters are always useful for the code analysis. In this case, `getMemberTypes` should be used. GitOrigin-RevId: 2455ed05099842fc50e1fa2a196c4952b6444795
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9094c7acdc
commit
abe6184e8a
@@ -5,12 +5,16 @@ import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.types.PyCallableType;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.PyTypedResolveResult;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@@ -72,4 +76,11 @@ public interface PyTypeProvider {
|
||||
@Nullable Ref<@Nullable PyCallableType> prepareCalleeTypeForCall(@Nullable PyType type,
|
||||
@NotNull PyCallExpression call,
|
||||
@NotNull TypeEvalContext context);
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@Nullable List<@NotNull PyTypedResolveResult> getMemberTypes(@NotNull PyType type,
|
||||
@NotNull String name,
|
||||
@Nullable PyExpression location,
|
||||
@NotNull AccessDirection direction,
|
||||
@NotNull PyResolveContext context);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.psi.AccessDirection;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyQualifiedNameOwner;
|
||||
import com.jetbrains.python.psi.PyTypedElement;
|
||||
import com.jetbrains.python.psi.impl.PyTypeProvider;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -36,22 +39,53 @@ public interface PyType {
|
||||
/**
|
||||
* Resolves an attribute of type.
|
||||
*
|
||||
* @param name attribute name
|
||||
* @param location the expression of type qualifierType on which the member is being resolved (optional)
|
||||
* @param name attribute name
|
||||
* @param location the expression of type qualifierType on which the member is being resolved (optional)
|
||||
* @return null if name definitely cannot be found (e.g. in a qualified reference),
|
||||
* or an empty list if name is not found but other contexts are worth looking at,
|
||||
* or a list of elements that define the name, a la multiResolve().
|
||||
* or an empty list if name is not found but other contexts are worth looking at,
|
||||
* or a list of elements that define the name, a la multiResolve().
|
||||
*/
|
||||
@Nullable
|
||||
List<? extends RatedResolveResult> resolveMember(@NotNull String name, final @Nullable PyExpression location,
|
||||
final @NotNull AccessDirection direction, final @NotNull PyResolveContext resolveContext);
|
||||
List<? extends RatedResolveResult> resolveMember(@NotNull String name,
|
||||
final @Nullable PyExpression location,
|
||||
final @NotNull AccessDirection direction,
|
||||
final @NotNull PyResolveContext resolveContext);
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@Nullable
|
||||
default List<@NotNull PyTypedResolveResult> getMemberTypes(@NotNull String name,
|
||||
final @Nullable PyExpression location,
|
||||
final @NotNull AccessDirection direction,
|
||||
final @NotNull PyResolveContext context) {
|
||||
for (PyTypeProvider typeProvider : PyTypeProvider.EP_NAME.getExtensionList()) {
|
||||
List<PyTypedResolveResult> types = typeProvider.getMemberTypes(this, name, location, direction, context);
|
||||
if (types != null) {
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
List<? extends RatedResolveResult> results = resolveMember(name, location, direction, context);
|
||||
if (results == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ContainerUtil.map(results, result -> {
|
||||
PsiElement element = result.getElement();
|
||||
if (element instanceof PyTypedElement typedElement) {
|
||||
return new PyTypedResolveResult(typedElement,
|
||||
context.getTypeEvalContext().getType(typedElement));
|
||||
}
|
||||
else {
|
||||
return new PyTypedResolveResult(element, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Proposes completion variants from type's attributes.
|
||||
*
|
||||
*
|
||||
* @param location the reference on which the completion was invoked
|
||||
* @param context to share state between nested invocations
|
||||
* @param location the reference on which the completion was invoked
|
||||
* @param context to share state between nested invocations
|
||||
* @return completion variants good for {@link com.intellij.psi.PsiReference#getVariants} return value.
|
||||
*/
|
||||
Object[] getCompletionVariants(String completionPrefix, PsiElement location, ProcessingContext context);
|
||||
@@ -63,9 +97,12 @@ public interface PyType {
|
||||
|
||||
/**
|
||||
* TODO rename it to something like getPresentableName(), because it's not clear that these names are actually visible to end-user
|
||||
*
|
||||
* @return name of the type
|
||||
*/
|
||||
@Nullable @NlsSafe String getName();
|
||||
@Nullable
|
||||
@NlsSafe
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* @return true if the type is a known built-in type.
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.FactoryMap;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyTypeProvider;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -82,6 +83,15 @@ public class PyTypeProviderBase implements PyTypeProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<@NotNull PyTypedResolveResult> getMemberTypes(@NotNull PyType type,
|
||||
@NotNull String name,
|
||||
@Nullable PyExpression location,
|
||||
@NotNull AccessDirection direction,
|
||||
@NotNull PyResolveContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void registerSelfReturnType(@NotNull String classQualifiedName, @NotNull Collection<String> methods) {
|
||||
registerReturnType(classQualifiedName, methods, mySelfTypeCallback);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.psi.types
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.ResolveResult
|
||||
|
||||
class PyTypedResolveResult(private val el: PsiElement?, val type: PyType?) : ResolveResult {
|
||||
override fun getElement(): PsiElement? {
|
||||
return el
|
||||
}
|
||||
override fun isValidResult(): Boolean {
|
||||
return element != null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user