mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'type-eval-contexts'
This commit is contained in:
@@ -56,7 +56,7 @@ public class PyResolveContext {
|
||||
}
|
||||
|
||||
public TypeEvalContext getTypeEvalContext() {
|
||||
return myTypeEvalContext != null ? myTypeEvalContext : TypeEvalContext.fastStubOnly(null);
|
||||
return myTypeEvalContext != null ? myTypeEvalContext : TypeEvalContext.codeInsightFallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -53,25 +53,43 @@ public class TypeEvalContext {
|
||||
return myAllowDataFlow || element.getContainingFile() == myOrigin;
|
||||
}
|
||||
|
||||
public static TypeEvalContext slow() {
|
||||
/**
|
||||
* Create the most detailed type evaluation context for user-initiated actions.
|
||||
*
|
||||
* Should be used for code completion, go to definition, find usages, refactorings, documentation.
|
||||
*/
|
||||
public static TypeEvalContext userInitiated() {
|
||||
return new TypeEvalContext(true, true, null);
|
||||
}
|
||||
|
||||
public static TypeEvalContext fast() {
|
||||
return new TypeEvalContext(false, true, null);
|
||||
/**
|
||||
* Create a type evaluation context for performing analysis operations on the specified file which is currently open in the editor,
|
||||
* without accessing stubs. For such a file, additional slow operations are allowed.
|
||||
*
|
||||
* Inspections should not create a new type evaluation context. They should re-use the context of the inspection session.
|
||||
*/
|
||||
public static TypeEvalContext codeAnalysis(@Nullable PsiFile origin) {
|
||||
return new TypeEvalContext(false, false, origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TypeEvalContext for performing analysis operations on the specified file which is currently open in the editor,
|
||||
* without accessing stubs. For such a file, additional slow operations are allowed.
|
||||
* Create the most shallow type evaluation context for code insight purposes when other more detailed contexts are not available.
|
||||
*
|
||||
* @param origin the file open in the editor
|
||||
* @return the type eval context for the file.
|
||||
* It's use should be minimized.
|
||||
*/
|
||||
public static TypeEvalContext fastStubOnly(@Nullable PsiFile origin) {
|
||||
return new TypeEvalContext(false, false, origin);
|
||||
public static TypeEvalContext codeInsightFallback() {
|
||||
return new TypeEvalContext(false, false, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a type evaluation context for deeper and slower code insight.
|
||||
*
|
||||
* Should be used only when normal code insight context is not enough for getting good results.
|
||||
*/
|
||||
public static TypeEvalContext deepCodeInsight() {
|
||||
return new TypeEvalContext(false, true, null);
|
||||
}
|
||||
|
||||
public TypeEvalContext withTracing() {
|
||||
if (myTrace == null) {
|
||||
myTrace = new ArrayList<String>();
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor {
|
||||
if (callee == null) return;
|
||||
final String name = callee.getText();
|
||||
if ("dict".equals(name)) {
|
||||
final TypeEvalContext context = TypeEvalContext.fast();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
final PyType type = context.getType(dictConstructor);
|
||||
if (type != null && type.isBuiltin(context)) {
|
||||
final PyArgumentList list = dictConstructor.getArgumentList();
|
||||
|
||||
+4
-2
@@ -145,10 +145,12 @@ public class ImportFromToImportIntention implements IntentionAction {
|
||||
PyReferenceExpression ref = import_element.getImportReferenceExpression();
|
||||
if (ref != null && ref.isValid()) {
|
||||
PsiElement target = ref.getReference().resolve();
|
||||
if (target instanceof PyExpression && TypeEvalContext.fast().getType((PyExpression)target) instanceof PyModuleType) return false;
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(file);
|
||||
if (target instanceof PyExpression && context.getType((PyExpression)target) instanceof PyModuleType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (info.myModuleReference != null) {
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public class PyDictConstructorToLiteralFormIntention extends BaseIntentionAction
|
||||
PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyCallExpression.class);
|
||||
|
||||
if (expression != null && expression.isCalleeText("dict")) {
|
||||
final TypeEvalContext context = TypeEvalContext.fast();
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(file);
|
||||
PyType type = context.getType(expression);
|
||||
if (type != null && type.isBuiltin(context)) {
|
||||
PyExpression[] argumentList = expression.getArguments();
|
||||
|
||||
+2
-2
@@ -66,9 +66,9 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction
|
||||
}
|
||||
if (expression instanceof PyStringLiteralExpression)
|
||||
continue;
|
||||
final PyType type = TypeEvalContext.fastStubOnly(file).getType(expression);
|
||||
final PyType type = TypeEvalContext.codeAnalysis(file).getType(expression);
|
||||
final boolean isStringReference = PyTypeChecker.match(cache.getStringType(LanguageLevel.forElement(expression)),
|
||||
type, TypeEvalContext.fastStubOnly(file)) && type != null;
|
||||
type, TypeEvalContext.codeAnalysis(file)) && type != null;
|
||||
if (!isStringReference) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class TypeAssertionIntention implements IntentionAction {
|
||||
(reference != null && reference.resolve() == null)) {
|
||||
return false;
|
||||
}
|
||||
final PyType type = TypeEvalContext.fastStubOnly(file).getType(problemElement);
|
||||
final PyType type = TypeEvalContext.codeAnalysis(file).getType(problemElement);
|
||||
return (type == null || type instanceof PyReturnTypeReference);
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
}
|
||||
|
||||
protected PyResolveContext getResolveContext(@NotNull PsiElement origin) {
|
||||
return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(origin.getContainingFile()));
|
||||
return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(origin.getContainingFile()));
|
||||
}
|
||||
|
||||
public boolean startInWriteAction() {
|
||||
|
||||
@@ -196,7 +196,7 @@ public class PyOverrideImplementUtil {
|
||||
statementBody.append(PyNames.PASS);
|
||||
}
|
||||
else {
|
||||
if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(TypeEvalContext.slow(), null) != PyNoneType.INSTANCE) {
|
||||
if (!PyNames.INIT.equals(baseFunction.getName()) && baseFunction.getReturnType(TypeEvalContext.userInitiated(), null) != PyNoneType.INSTANCE) {
|
||||
statementBody.append("return ");
|
||||
}
|
||||
if (baseClass.isNewStyleClass()) {
|
||||
|
||||
@@ -87,30 +87,30 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
return getReturnTypeByQName(qname, function);
|
||||
return getReturnTypeByQName(qname, function, context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyType getConstructorType(@NotNull PyClass cls) {
|
||||
public PyType getConstructorType(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
|
||||
final String classQName = cls.getQualifiedName();
|
||||
if (classQName != null) {
|
||||
final PyQualifiedName canonicalQName = PyStdlibCanonicalPathProvider.restoreStdlibCanonicalPath(PyQualifiedName.fromDottedString(classQName));
|
||||
if (canonicalQName != null) {
|
||||
final PyQualifiedName qname = canonicalQName.append(PyNames.INIT);
|
||||
return getReturnTypeByQName(qname.toString(), cls);
|
||||
return getReturnTypeByQName(qname.toString(), cls, context);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyType getReturnTypeByQName(@NotNull String qname, @NotNull PsiElement anchor) {
|
||||
private PyType getReturnTypeByQName(@NotNull String qname, @NotNull PsiElement anchor, @NotNull TypeEvalContext context) {
|
||||
final LanguageLevel level = LanguageLevel.forElement(anchor);
|
||||
final String key = String.format("Python%d/%s.return", level.getVersion(), qname);
|
||||
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
|
||||
final Ref<PyType> cached = cache.getStdlibType(key);
|
||||
final Ref<PyType> cached = cache.getStdlibType(key, context);
|
||||
if (cached != null) {
|
||||
return cached.get();
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
final String name = param.getName();
|
||||
final String qname = getQualifiedName(func, param);
|
||||
if (qname != null && name != null) {
|
||||
return getParameterTypeByQName(qname, name, func);
|
||||
return getParameterTypeByQName(qname, name, func, context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -175,7 +175,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
PyType rtype;
|
||||
do {
|
||||
final String overloadedQName = String.format("%s.%d", qname, i);
|
||||
rtype = getReturnTypeByQName(overloadedQName, anchor);
|
||||
rtype = getReturnTypeByQName(overloadedQName, anchor, context);
|
||||
if (rtype != null) {
|
||||
boolean matched = true;
|
||||
boolean notNullParameterMatch = false;
|
||||
@@ -192,7 +192,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
continue;
|
||||
}
|
||||
final PyType argType = context.getType(entry.getKey());
|
||||
final PyType paramType = getParameterTypeByQName(overloadedQName, name, anchor);
|
||||
final PyType paramType = getParameterTypeByQName(overloadedQName, name, anchor, context);
|
||||
if (PyTypeChecker.match(paramType, argType, context)) {
|
||||
if (paramType != null && !PyTypeChecker.isUnknown(argType)) {
|
||||
notNullParameterMatch = true;
|
||||
@@ -230,7 +230,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
|
||||
final LanguageLevel level = LanguageLevel.forElement(anchor);
|
||||
final PyType paramType = getParameterTypeByQName(overloadedQName, "mode", anchor);
|
||||
final PyType paramType = getParameterTypeByQName(overloadedQName, "mode", anchor, context);
|
||||
final PyType argType;
|
||||
// Binary mode
|
||||
if (mode.contains("b")) {
|
||||
@@ -249,11 +249,14 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyType getParameterTypeByQName(@NotNull String functionQName, @NotNull String name, @NotNull PsiElement anchor) {
|
||||
private PyType getParameterTypeByQName(@NotNull String functionQName,
|
||||
@NotNull String name,
|
||||
@NotNull PsiElement anchor,
|
||||
@NotNull TypeEvalContext context) {
|
||||
final LanguageLevel level = LanguageLevel.forElement(anchor);
|
||||
final String key = String.format("Python%d/%s.%s", level.getVersion(), functionQName, name);
|
||||
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
|
||||
final Ref<PyType> cached = cache.getStdlibType(key);
|
||||
final Ref<PyType> cached = cache.getStdlibType(key, context);
|
||||
if (cached != null) {
|
||||
return cached.get();
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase<PsiEleme
|
||||
for (PyImportElement element : elements) {
|
||||
final PyReferenceExpression referenceExpression = element.getImportReferenceExpression();
|
||||
if (referenceExpression == null) continue;
|
||||
final PyType type = TypeEvalContext.fast().getType(referenceExpression);
|
||||
final PyType type = TypeEvalContext.userInitiated().getType(referenceExpression);
|
||||
if (type instanceof PyClassType) {
|
||||
variants.add(((PyClassType)type).getPyClass());
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class PyDocumentationBuilder {
|
||||
if (outer instanceof PyQualifiedExpression) {
|
||||
PyExpression qual = ((PyQualifiedExpression)outer).getQualifier();
|
||||
if (qual != null) {
|
||||
PyType type = TypeEvalContext.fast().getType(qual);
|
||||
PyType type = TypeEvalContext.userInitiated().getType(qual);
|
||||
if (type instanceof PyClassType) {
|
||||
cls = ((PyClassType)type).getPyClass();
|
||||
Property property = cls.findProperty(elementName);
|
||||
@@ -190,7 +190,7 @@ class PyDocumentationBuilder {
|
||||
myBody.addItem(combUp("Parameter " + PyUtil.getReadableRepr(followed, false)));
|
||||
boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)followed);
|
||||
if (outer instanceof PyExpression) {
|
||||
TypeEvalContext context = TypeEvalContext.slow();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
PyType type = context.getType((PyExpression)outer);
|
||||
if (type != null) {
|
||||
String s = null;
|
||||
@@ -216,14 +216,14 @@ class PyDocumentationBuilder {
|
||||
if (s != null) {
|
||||
myBody
|
||||
.addItem(combUp(s));
|
||||
PythonDocumentationProvider.describeTypeWithLinks(myBody, followed, type, TypeEvalContext.slow());
|
||||
PythonDocumentationProvider.describeTypeWithLinks(myBody, followed, type, TypeEvalContext.userInitiated());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (followed != null && outer instanceof PyReferenceExpression) {
|
||||
myBody.addItem(combUp("\nInferred type: "));
|
||||
PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outer, TypeEvalContext.slow());
|
||||
PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outer, TypeEvalContext.userInitiated());
|
||||
}
|
||||
if (myBody.isEmpty() && myEpilog.isEmpty()) {
|
||||
return null; // got nothing substantial to say!
|
||||
|
||||
@@ -148,18 +148,18 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
|
||||
}
|
||||
|
||||
static String describeExpressionType(PyExpression expr) {
|
||||
final TypeEvalContext context = TypeEvalContext.slow();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
return String.format("Inferred type: %s", getTypeName(context.getType(expr), context));
|
||||
}
|
||||
|
||||
public static String getTypeDescription(@NotNull PyFunction fun) {
|
||||
final TypeEvalContext context = TypeEvalContext.slow();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
PyTypeModelBuilder builder = new PyTypeModelBuilder(context);
|
||||
return builder.build(fun).asString();
|
||||
}
|
||||
|
||||
public static void getTypeDescription(@NotNull PyFunction fun, ChainIterable<String> body) {
|
||||
final TypeEvalContext context = TypeEvalContext.slow();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
PyTypeModelBuilder builder = new PyTypeModelBuilder(context);
|
||||
builder.build(fun).toBodyWithLinks(body, fun);
|
||||
}
|
||||
@@ -481,7 +481,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
|
||||
@Nullable
|
||||
private static PyClass inferClassOfParameter(PsiElement context) {
|
||||
if (context instanceof PyNamedParameter) {
|
||||
final PyType type = TypeEvalContext.fast().getType((PyNamedParameter)context);
|
||||
final PyType type = TypeEvalContext.userInitiated().getType((PyNamedParameter)context);
|
||||
if (type instanceof PyClassType) {
|
||||
return ((PyClassType)type).getPyClass();
|
||||
}
|
||||
|
||||
@@ -39,11 +39,12 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx {
|
||||
if (element instanceof PyQualifiedExpression) {
|
||||
final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier();
|
||||
if (qualifier != null) {
|
||||
final PyType type = TypeEvalContext.fast().getType(qualifier);
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
final PyType type = context.getType(qualifier);
|
||||
if (type == null || type instanceof PyTypeReference) {
|
||||
final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class);
|
||||
if (call != null && element == call.getCallee()) {
|
||||
return checkMatchingSignatureGroup(call, targets);
|
||||
return checkMatchingSignatureGroup(call, targets, context);
|
||||
}
|
||||
return UNTYPED;
|
||||
}
|
||||
@@ -74,7 +75,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UsageType checkMatchingSignatureGroup(PyCallExpression call, UsageTarget[] targets) {
|
||||
private static UsageType checkMatchingSignatureGroup(PyCallExpression call, UsageTarget[] targets, TypeEvalContext context) {
|
||||
if (targets.length == 1 && targets[0] instanceof PsiElementUsageTarget) {
|
||||
final PsiElement element = ((PsiElementUsageTarget)targets[0]).getElement();
|
||||
if (element instanceof PyFunction) {
|
||||
@@ -82,7 +83,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx {
|
||||
final PyFunction.Modifier modifier = function.getModifier();
|
||||
PyCallExpression.PyMarkedCallee callee = new PyCallExpression.PyMarkedCallee(function, modifier, 1, true);
|
||||
CallArgumentsMappingImpl mapping = new CallArgumentsMappingImpl(call.getArgumentList());
|
||||
mapping.mapArguments(callee, null);
|
||||
mapping.mapArguments(callee, context);
|
||||
if (mapping.hasProblems()) {
|
||||
return SIGNATURE_MISMATCH;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import com.jetbrains.python.psi.PyStringLiteralExpression;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.PyTypeChecker;
|
||||
import com.jetbrains.python.psi.types.PyTypeParser;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -98,10 +97,10 @@ public class PyDocstringTypesInspection extends PyInspection {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean match(PsiElement anchor, String dynamicTypeName, String specifiedTypeName) {
|
||||
private boolean match(PsiElement anchor, String dynamicTypeName, String specifiedTypeName) {
|
||||
final PyType dynamicType = PyTypeParser.getTypeByName(anchor, dynamicTypeName);
|
||||
final PyType specifiedType = PyTypeParser.getTypeByName(anchor, specifiedTypeName);
|
||||
return PyTypeChecker.match(specifiedType, dynamicType, TypeEvalContext.slow());
|
||||
return PyTypeChecker.match(specifiedType, dynamicType, myTypeEvalContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public abstract class PyInspectionVisitor extends PyElementVisitor {
|
||||
synchronized (INSPECTION_TYPE_EVAL_CONTEXT) {
|
||||
context = session.getUserData(INSPECTION_TYPE_EVAL_CONTEXT);
|
||||
if (context == null) {
|
||||
context = TypeEvalContext.fastStubOnly(session.getFile());
|
||||
context = TypeEvalContext.codeAnalysis(session.getFile());
|
||||
session.putUserData(INSPECTION_TYPE_EVAL_CONTEXT, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,15 +64,22 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
final Map<PyGenericType, PyType> substitutions = new LinkedHashMap<PyGenericType, PyType>();
|
||||
final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext);
|
||||
if (results != null) {
|
||||
substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getCallable(), results.getReceiver(), myTypeEvalContext));
|
||||
boolean genericsCollected = false;
|
||||
for (Map.Entry<PyExpression, PyNamedParameter> entry : results.getArguments().entrySet()) {
|
||||
final PyNamedParameter p = entry.getValue();
|
||||
if (p.isPositionalContainer() || p.isKeywordContainer()) {
|
||||
// TODO: Support *args, **kwargs
|
||||
continue;
|
||||
}
|
||||
final PyType argType = myTypeEvalContext.getType(entry.getKey());
|
||||
final PyType paramType = myTypeEvalContext.getType(p);
|
||||
if (paramType == null) {
|
||||
continue;
|
||||
}
|
||||
final PyType argType = myTypeEvalContext.getType(entry.getKey());
|
||||
if (!genericsCollected) {
|
||||
substitutions.putAll(PyTypeChecker.collectCallGenerics(results.getCallable(), results.getReceiver(), myTypeEvalContext));
|
||||
genericsCollected = true;
|
||||
}
|
||||
checkTypes(paramType, argType, entry.getKey(), myTypeEvalContext, substitutions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,13 +640,13 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
|
||||
}
|
||||
if (qtype instanceof PyClassTypeImpl) {
|
||||
PyClass cls = ((PyClassType)qtype).getPyClass();
|
||||
if (overridesGetAttr(cls)) {
|
||||
if (overridesGetAttr(cls, myTypeEvalContext)) {
|
||||
return true;
|
||||
}
|
||||
if (cls.findProperty(refText) != null) {
|
||||
return true;
|
||||
}
|
||||
if (PyUtil.hasUnresolvedAncestors(cls)) {
|
||||
if (PyUtil.hasUnresolvedAncestors(cls, myTypeEvalContext)) {
|
||||
return true;
|
||||
}
|
||||
if (isDecoratedAsDynamic(cls, true)) {
|
||||
@@ -811,13 +811,11 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name) {
|
||||
final TypeEvalContext context = TypeEvalContext.fastStubOnly(null);
|
||||
private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name, @NotNull TypeEvalContext context) {
|
||||
final PyType type = context.getType(cls);
|
||||
if (type != null) {
|
||||
final List<? extends RatedResolveResult> results = type.resolveMember(name, null, AccessDirection.READ,
|
||||
PyResolveContext.noImplicits().withTypeEvalContext(context)
|
||||
);
|
||||
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
|
||||
final List<? extends RatedResolveResult> results = type.resolveMember(name, null, AccessDirection.READ, resolveContext);
|
||||
if (results != null && !results.isEmpty()) {
|
||||
return results.get(0).getElement();
|
||||
}
|
||||
@@ -825,12 +823,12 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean overridesGetAttr(@NotNull PyClass cls) {
|
||||
PsiElement method = resolveClassMember(cls, PyNames.GETATTR);
|
||||
private static boolean overridesGetAttr(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
|
||||
PsiElement method = resolveClassMember(cls, PyNames.GETATTR, context);
|
||||
if (method != null) {
|
||||
return true;
|
||||
}
|
||||
method = resolveClassMember(cls, PyNames.GETATTRIBUTE);
|
||||
method = resolveClassMember(cls, PyNames.GETATTRIBUTE, context);
|
||||
if (method != null && !PyBuiltinCache.getInstance(cls).hasInBuiltins(method)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class AddMethodQuickFix implements LocalQuickFix {
|
||||
boolean made_instance = false;
|
||||
if (call_by_class) {
|
||||
if (args.length > 0) {
|
||||
PyType first_arg_type = TypeEvalContext.fast().getType(args[0]);
|
||||
PyType first_arg_type = TypeEvalContext.userInitiated().getType(args[0]);
|
||||
if (first_arg_type instanceof PyClassType && ((PyClassType)first_arg_type).getPyClass().isSubclass(cls)) {
|
||||
// class, first arg ok: instance method
|
||||
builder.parameter("self"); // NOTE: might use a name other than 'self', according to code style.
|
||||
|
||||
@@ -617,8 +617,8 @@ public class PyUtil {
|
||||
: psiNamedElement.getName();
|
||||
}
|
||||
|
||||
public static boolean hasUnresolvedAncestors(@NotNull PyClass cls) {
|
||||
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
public static boolean hasUnresolvedAncestors(@NotNull PyClass cls, @NotNull TypeEvalContext context) {
|
||||
for (PyClassLikeType type : cls.getAncestorTypes(context)) {
|
||||
if (type == null) {
|
||||
return true;
|
||||
}
|
||||
@@ -998,7 +998,7 @@ public class PyUtil {
|
||||
if (isBaseException(pyClass.getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
|
||||
if (type != null && isBaseException(type.getClassQName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -47,14 +47,10 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
|
||||
* positional paramaters, but at least one item long.
|
||||
* @param arguments what to map, get if from call site
|
||||
* @param resolved_callee what to map parameters of
|
||||
* @param type_context optional shared type evaluator / cache.
|
||||
* @param context optional shared type evaluator / cache.
|
||||
*/
|
||||
public void mapArguments(
|
||||
PyCallExpression.PyMarkedCallee resolved_callee,
|
||||
@Nullable TypeEvalContext type_context
|
||||
) {
|
||||
public void mapArguments(PyCallExpression.PyMarkedCallee resolved_callee, @Nullable TypeEvalContext context) {
|
||||
PyExpression[] arguments = myArgumentList.getArguments();
|
||||
if (type_context == null) type_context = TypeEvalContext.fast();
|
||||
myMarkedCallee = resolved_callee;
|
||||
List<PyExpression> unmatched_args = new LinkedList<PyExpression>();
|
||||
Collections.addAll(unmatched_args, arguments);
|
||||
@@ -144,8 +140,8 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
|
||||
mapped_args.add(arg); // tuple itself is always mapped; its insides can fail
|
||||
}
|
||||
else {
|
||||
PyType arg_type = type_context.getType(arg);
|
||||
if (arg_type != null && arg_type.isBuiltin(type_context) && "list".equals(arg_type.getName())) {
|
||||
PyType arg_type = context.getType(arg);
|
||||
if (arg_type != null && arg_type.isBuiltin(context) && "list".equals(arg_type.getName())) {
|
||||
mapped_args.add(arg); // we can't really analyze arbitrary lists statically yet
|
||||
// but ListLiteralExpressions are handled by visitor
|
||||
}
|
||||
@@ -210,10 +206,10 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
|
||||
if (cnt < parameters.length && cnt < positional_index && myTupleArg != null) {
|
||||
// check length of myTupleArg
|
||||
PyType tuple_arg_type = null;
|
||||
if (type_context != null) {
|
||||
if (context != null) {
|
||||
final PyExpression expression = PsiTreeUtil.getChildOfType(myTupleArg, PyExpression.class);
|
||||
if (expression != null) {
|
||||
tuple_arg_type = type_context.getType(expression);
|
||||
tuple_arg_type = context.getType(expression);
|
||||
}
|
||||
}
|
||||
int tuple_length;
|
||||
|
||||
@@ -131,8 +131,12 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
|
||||
offset = getTextRange().getStartOffset() + offset - element.getTextRange().getStartOffset();
|
||||
|
||||
List<PsiReference> referencesList = new ArrayList<PsiReference>();
|
||||
final PsiFile file = element.getContainingFile();
|
||||
final PyResolveContext resolveContext = file != null ?
|
||||
PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(file)) :
|
||||
PyResolveContext.defaultContext();
|
||||
while (element != null) {
|
||||
addReferences(offset, element, referencesList);
|
||||
addReferences(offset, element, referencesList, resolveContext);
|
||||
offset = element.getStartOffsetInParent() + offset;
|
||||
if (element instanceof PsiFile) break;
|
||||
element = element.getParent();
|
||||
@@ -144,14 +148,11 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
|
||||
referencesList.get(referencesList.size() - 1).getElement());
|
||||
}
|
||||
|
||||
private static void addReferences(int offset, PsiElement element, final Collection<PsiReference> outReferences) {
|
||||
private static void addReferences(int offset, PsiElement element, final Collection<PsiReference> outReferences,
|
||||
PyResolveContext resolveContext) {
|
||||
final PsiReference[] references;
|
||||
if (element instanceof PyReferenceOwner) {
|
||||
final PsiFile file = element.getContainingFile();
|
||||
final PyResolveContext context = file != null ?
|
||||
PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(file)) :
|
||||
PyResolveContext.defaultContext();
|
||||
final PsiPolyVariantReference reference = ((PyReferenceOwner)element).getReference(context);
|
||||
final PsiPolyVariantReference reference = ((PyReferenceOwner)element).getReference(resolveContext);
|
||||
references = reference == null ? PsiReference.EMPTY_ARRAY : new PsiReference[] {reference};
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -314,11 +314,11 @@ public class PyBuiltinCache {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Ref<PyType> getStdlibType(@NotNull String key) {
|
||||
public Ref<PyType> getStdlibType(@NotNull String key, @NotNull TypeEvalContext context) {
|
||||
synchronized (myStdlibTypeCache) {
|
||||
final Ref<PyType> ref = myStdlibTypeCache.get(key);
|
||||
if (ref != null) {
|
||||
if (!isValid(ref.get())) {
|
||||
if (!isValid(ref.get(), context)) {
|
||||
myStdlibTypeCache.clear();
|
||||
return null;
|
||||
}
|
||||
@@ -327,10 +327,10 @@ public class PyBuiltinCache {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValid(@Nullable PyType type) {
|
||||
private static boolean isValid(@Nullable PyType type, @NotNull TypeEvalContext context) {
|
||||
if (type instanceof PyCollectionType) {
|
||||
final PyType elementType = ((PyCollectionType)type).getElementType(TypeEvalContext.fastStubOnly(null));
|
||||
if (!isValid(elementType)) {
|
||||
final PyType elementType = ((PyCollectionType)type).getElementType(context);
|
||||
if (!isValid(elementType, context)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -340,7 +340,7 @@ public class PyBuiltinCache {
|
||||
}
|
||||
else if (type instanceof PyUnionType) {
|
||||
for (PyType member : ((PyUnionType)type).getMembers()) {
|
||||
if (!isValid(member)) {
|
||||
if (!isValid(member, context)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<List<PyClassLikeType>> compute() {
|
||||
final TypeEvalContext context = myCachedContext != null ? myCachedContext : TypeEvalContext.fastStubOnly(null);
|
||||
final TypeEvalContext context = myCachedContext != null ? myCachedContext : TypeEvalContext.codeInsightFallback();
|
||||
final List<PyClassLikeType> ancestorTypes = isNewStyleClass() ? getMROAncestorTypes(context) : getOldStyleAncestorTypes(context);
|
||||
return Result.create(ancestorTypes, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
|
||||
}
|
||||
@@ -194,7 +194,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
@NotNull
|
||||
@Override
|
||||
public List<PyClass> getAncestorClasses() {
|
||||
return getAncestorClasses(TypeEvalContext.fastStubOnly(null));
|
||||
return getAncestorClasses(TypeEvalContext.codeInsightFallback());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -224,7 +224,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
if (superClassQName.equals(getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
for (PyClassLikeType type : getAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
for (PyClassLikeType type : getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
|
||||
if (type != null && superClassQName.equals(type.getClassQName())) {
|
||||
return true;
|
||||
}
|
||||
@@ -287,7 +287,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
|
||||
@NotNull
|
||||
public PyClass[] getSuperClasses() {
|
||||
final List<PyClassLikeType> superTypes = getSuperClassTypes(TypeEvalContext.fastStubOnly(null));
|
||||
final List<PyClassLikeType> superTypes = getSuperClassTypes(TypeEvalContext.codeInsightFallback());
|
||||
if (superTypes.isEmpty()) {
|
||||
return EMPTY_ARRAY;
|
||||
}
|
||||
@@ -925,7 +925,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
final PyClass objClass = PyBuiltinCache.getInstance(this).getClass("object");
|
||||
if (this == objClass) return true; // a rare but possible case
|
||||
if (hasNewStyleMetaClass(this)) return true;
|
||||
for (PyClassLikeType type : getOldStyleAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
for (PyClassLikeType type : getOldStyleAncestorTypes(TypeEvalContext.codeInsightFallback())) {
|
||||
if (type == null) {
|
||||
// unknown, assume new-style class
|
||||
return true;
|
||||
|
||||
@@ -179,7 +179,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
|
||||
else {
|
||||
final PyStdlibTypeProvider stdlib = PyStdlibTypeProvider.getInstance();
|
||||
if (stdlib != null) {
|
||||
initType = stdlib.getConstructorType(containingClass);
|
||||
initType = stdlib.getConstructorType(containingClass, context);
|
||||
}
|
||||
}
|
||||
if (initType != null && !(initType instanceof PyNoneType || initType instanceof PyReturnTypeReference)) {
|
||||
|
||||
@@ -138,12 +138,13 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
if (elt instanceof PyTargetExpression) {
|
||||
PsiElement assigned_from = null;
|
||||
final PyTargetExpression expr = (PyTargetExpression)elt;
|
||||
if (resolveContext.getTypeEvalContext().maySwitchToAST(expr) || expr.getStub() == null) {
|
||||
final TypeEvalContext context = resolveContext.getTypeEvalContext();
|
||||
if (context.maySwitchToAST(expr) || expr.getStub() == null) {
|
||||
assigned_from = expr.findAssignedValue();
|
||||
}
|
||||
// TODO: Maybe findAssignedValueByStub() should become a part of the PyTargetExpression interface
|
||||
else if (elt instanceof PyTargetExpressionImpl) {
|
||||
assigned_from = ((PyTargetExpressionImpl)elt).findAssignedValueByStub();
|
||||
assigned_from = ((PyTargetExpressionImpl)elt).findAssignedValueByStub(context);
|
||||
}
|
||||
if (assigned_from instanceof PyReferenceExpression) {
|
||||
if (visited.contains(assigned_from)) {
|
||||
|
||||
@@ -118,7 +118,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
return pyType;
|
||||
}
|
||||
if (!context.maySwitchToAST(this)) {
|
||||
final PsiElement value = getStub() != null ? findAssignedValueByStub() : findAssignedValue();
|
||||
final PsiElement value = getStub() != null ? findAssignedValueByStub(context) : findAssignedValue();
|
||||
if (value instanceof PyTypedElement) {
|
||||
return context.getType((PyTypedElement)value);
|
||||
}
|
||||
@@ -438,7 +438,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement findAssignedValueByStub() {
|
||||
public PsiElement findAssignedValueByStub(@NotNull TypeEvalContext context) {
|
||||
final PyTargetExpressionStub stub = getStub();
|
||||
if (stub != null && stub.getInitializerType() == PyTargetExpressionStub.InitializerType.ReferenceExpression) {
|
||||
final PyQualifiedName initializer = stub.getInitializer();
|
||||
@@ -451,7 +451,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
return ((PyFile)parent).getElementNamed(name);
|
||||
}
|
||||
else if (parent instanceof PyClass) {
|
||||
final PyType type = TypeEvalContext.fastStubOnly(null).getType((PyClass)parent);
|
||||
final PyType type = context.getType((PyClass)parent);
|
||||
if (type != null) {
|
||||
final List<? extends RatedResolveResult> results = type.resolveMember(name, null, AccessDirection.READ,
|
||||
PyResolveContext.noImplicits());
|
||||
|
||||
@@ -81,9 +81,10 @@ public class PyImportReference extends PyReferenceImpl {
|
||||
}
|
||||
|
||||
PyExpression qualifier = myElement.getQualifier();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
if (qualifier != null) {
|
||||
// qualifier's type must be module, it should know how to complete
|
||||
PyType type = TypeEvalContext.fast().getType(qualifier);
|
||||
PyType type = context.getType(qualifier);
|
||||
if (type != null) {
|
||||
Object[] variants = getTypeCompletionVariants(myElement, type);
|
||||
if (!alreadyHasImportKeyword()) {
|
||||
@@ -97,7 +98,7 @@ public class PyImportReference extends PyReferenceImpl {
|
||||
}
|
||||
else {
|
||||
// complete to possible modules
|
||||
return new ImportVariantCollector().execute();
|
||||
return new ImportVariantCollector(context).execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,8 +154,10 @@ public class PyImportReference extends PyReferenceImpl {
|
||||
private final PsiFile myCurrentFile;
|
||||
private final Set<String> myNamesAlready;
|
||||
private final List<Object> myObjects;
|
||||
@NotNull private final TypeEvalContext myContext;
|
||||
|
||||
public ImportVariantCollector() {
|
||||
public ImportVariantCollector(@NotNull TypeEvalContext context) {
|
||||
myContext = context;
|
||||
PsiFile currentFile = myElement.getContainingFile();
|
||||
if (currentFile != null) currentFile = currentFile.getOriginalFile();
|
||||
myCurrentFile = currentFile;
|
||||
@@ -177,7 +180,7 @@ public class PyImportReference extends PyReferenceImpl {
|
||||
addImportedNames(from_import.getImportElements()); // don't propose already imported items
|
||||
// try to collect submodules
|
||||
PyExpression module = (PyExpression)mod_candidate;
|
||||
PyType qualifierType = TypeEvalContext.fast().getType(module);
|
||||
PyType qualifierType = myContext.getType(module);
|
||||
if (qualifierType != null) {
|
||||
ProcessingContext ctx = new ProcessingContext();
|
||||
ctx.put(PyType.CTX_NAMES, myNamesAlready);
|
||||
|
||||
@@ -247,7 +247,7 @@ public class PyQualifiedReference extends PyReferenceImpl {
|
||||
}
|
||||
final PyQualifiedExpression element = CompletionUtil.getOriginalOrSelf(myElement);
|
||||
|
||||
PyType qualifierType = TypeEvalContext.slow().getType(qualifier);
|
||||
PyType qualifierType = TypeEvalContext.userInitiated().getType(qualifier);
|
||||
ProcessingContext ctx = new ProcessingContext();
|
||||
final Set<String> namesAlready = new HashSet<String>();
|
||||
ctx.put(PyType.CTX_NAMES, namesAlready);
|
||||
@@ -382,26 +382,26 @@ public class PyQualifiedReference extends PyReferenceImpl {
|
||||
return false;
|
||||
}
|
||||
final String referencedName = myElement.getReferencedName();
|
||||
if (element instanceof PyFunction && Comparing.equal(referencedName, ((PyFunction)element).getName()) &&
|
||||
((PyFunction)element).getContainingClass() != null && !PyNames.INIT.equals(referencedName)) {
|
||||
final PyExpression qualifier = myElement.getQualifier();
|
||||
if (qualifier != null) {
|
||||
final TypeEvalContext context = TypeEvalContext.fast();
|
||||
PyType qualifierType = context.getType(qualifier);
|
||||
if (qualifierType == null || qualifierType instanceof PyTypeReference) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
PyResolveContext resolveContext = myContext.withoutImplicits();
|
||||
// Guess type eval context origin for switching to local dataflow and return type analysis
|
||||
if (resolveContext.getTypeEvalContext().getOrigin() == null) {
|
||||
final PsiFile containingFile = myElement.getContainingFile();
|
||||
if (containingFile instanceof StubBasedPsiElement) {
|
||||
assert ((StubBasedPsiElement)containingFile).getStub() == null : "Stub origin for type eval context in isReferenceTo()";
|
||||
}
|
||||
final TypeEvalContext context = TypeEvalContext.fastStubOnly(containingFile);
|
||||
final TypeEvalContext context = TypeEvalContext.codeAnalysis(containingFile);
|
||||
resolveContext = resolveContext.withTypeEvalContext(context);
|
||||
}
|
||||
if (element instanceof PyFunction && Comparing.equal(referencedName, ((PyFunction)element).getName()) &&
|
||||
((PyFunction)element).getContainingClass() != null && !PyNames.INIT.equals(referencedName)) {
|
||||
final PyExpression qualifier = myElement.getQualifier();
|
||||
if (qualifier != null) {
|
||||
final PyType qualifierType = resolveContext.getTypeEvalContext().getType(qualifier);
|
||||
if (qualifierType == null || qualifierType instanceof PyTypeReference) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ResolveResult result : copyWithResolveContext(resolveContext).multiResolve(false)) {
|
||||
LOG.assertTrue(!(result instanceof ImplicitResolveResult));
|
||||
PsiElement resolveResult = result.getElement();
|
||||
|
||||
@@ -6,14 +6,16 @@ import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiInvalidElementAccessException;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.*;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -271,10 +273,10 @@ public class ResolveImportUtil {
|
||||
dir = (PsiDirectory)parent;
|
||||
}
|
||||
else if (parent != null) {
|
||||
PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, TypeEvalContext.fast(), null);
|
||||
final PyResolveContext resolveContext = PyResolveContext.defaultContext();
|
||||
PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, resolveContext.getTypeEvalContext(), null);
|
||||
if (refType != null) {
|
||||
final List<? extends RatedResolveResult> result = refType.resolveMember(referencedName, null, AccessDirection.READ,
|
||||
PyResolveContext.defaultContext());
|
||||
final List<? extends RatedResolveResult> result = refType.resolveMember(referencedName, null, AccessDirection.READ, resolveContext);
|
||||
if (result != null && !result.isEmpty()) {
|
||||
return result.get(0).getElement();
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
}
|
||||
|
||||
if (isDefinition() && myClass.isNewStyleClass()) {
|
||||
PyClassType typeType = getMetaclassType();
|
||||
PyClassType typeType = getMetaclassType(context);
|
||||
if (typeType != null) {
|
||||
List<? extends RatedResolveResult> typeMembers = typeType.resolveMember(name, location, direction, resolveContext);
|
||||
if (typeMembers != null && !typeMembers.isEmpty()) {
|
||||
@@ -237,10 +237,10 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyClassType getMetaclassType() {
|
||||
private PyClassType getMetaclassType(@NotNull TypeEvalContext context) {
|
||||
final PyTargetExpression metaClassAttribute = myClass.findClassAttribute(PyNames.DUNDER_METACLASS, true);
|
||||
if (metaClassAttribute != null) {
|
||||
final PyType type = TypeEvalContext.fastStubOnly(null).getType(metaClassAttribute);
|
||||
final PyType type = context.getType(metaClassAttribute);
|
||||
if (type instanceof PyClassType) {
|
||||
return (PyClassType)type;
|
||||
}
|
||||
@@ -348,7 +348,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
boolean suppressParentheses = context.get(CTX_SUPPRESS_PARENTHESES) != null;
|
||||
addOwnClassMembers(location, namesAlready, suppressParentheses, ret);
|
||||
|
||||
addInheritedMembers(prefix, location, namesAlready, context, ret);
|
||||
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated();
|
||||
addInheritedMembers(prefix, location, namesAlready, context, ret, typeEvalContext);
|
||||
|
||||
// from providers
|
||||
for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
|
||||
@@ -374,7 +375,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
}
|
||||
|
||||
if (isDefinition() && myClass.isNewStyleClass()) {
|
||||
PyClassType typeType = getMetaclassType();
|
||||
final PyClassType typeType = getMetaclassType(typeEvalContext);
|
||||
if (typeType != null) {
|
||||
Collections.addAll(ret, typeType.getCompletionVariants(prefix, location, context));
|
||||
}
|
||||
@@ -432,7 +433,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
PyExpression expressionHook,
|
||||
Set<String> namesAlready,
|
||||
ProcessingContext context,
|
||||
List<Object> ret) {
|
||||
List<Object> ret,
|
||||
@NotNull TypeEvalContext typeEvalContext) {
|
||||
for (PyExpression expression : myClass.getSuperClassExpressions()) {
|
||||
final PsiReference reference = expression.getReference();
|
||||
PsiElement element = null;
|
||||
@@ -444,7 +446,6 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
|
||||
type = new PyClassTypeImpl((PyClass)element, myIsDefinition);
|
||||
}
|
||||
else {
|
||||
final TypeEvalContext typeEvalContext = TypeEvalContext.fastStubOnly(myClass.getContainingFile());
|
||||
type = typeEvalContext.getType(expression);
|
||||
if (type instanceof PyClassType && !myIsDefinition) {
|
||||
type = ((PyClassType)type).toInstance();
|
||||
|
||||
@@ -104,7 +104,7 @@ public class PyTypeChecker {
|
||||
final PyClass superClass = ((PyClassType)expected).getPyClass();
|
||||
final PyClass subClass = ((PyClassType)actual).getPyClass();
|
||||
if (expected instanceof PyCollectionType && actual instanceof PyCollectionType) {
|
||||
if (!matchClasses(superClass, subClass)) {
|
||||
if (!matchClasses(superClass, subClass, context)) {
|
||||
return false;
|
||||
}
|
||||
final PyType superElementType = ((PyCollectionType)expected).getElementType(context);
|
||||
@@ -126,7 +126,7 @@ public class PyTypeChecker {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (matchClasses(superClass, subClass)) {
|
||||
else if (matchClasses(superClass, subClass, context)) {
|
||||
return true;
|
||||
}
|
||||
else if (((PyClassType)actual).isDefinition() && PyNames.CALLABLE.equals(expected.getName())) {
|
||||
@@ -287,7 +287,7 @@ public class PyTypeChecker {
|
||||
// Unify generics in stdlib pseudo-constructor
|
||||
final PyStdlibTypeProvider stdlib = PyStdlibTypeProvider.getInstance();
|
||||
if (stdlib != null) {
|
||||
final PyType initType = stdlib.getConstructorType(cls);
|
||||
final PyType initType = stdlib.getConstructorType(cls, context);
|
||||
if (initType != null) {
|
||||
match(initType, qualifierType, context, substitutions);
|
||||
}
|
||||
@@ -297,11 +297,11 @@ public class PyTypeChecker {
|
||||
return substitutions;
|
||||
}
|
||||
|
||||
private static boolean matchClasses(@Nullable PyClass superClass, @Nullable PyClass subClass) {
|
||||
private static boolean matchClasses(@Nullable PyClass superClass, @Nullable PyClass subClass, @NotNull TypeEvalContext context) {
|
||||
if (superClass == null || subClass == null || subClass.isSubclass(superClass) || PyABCUtil.isSubclass(subClass, superClass)) {
|
||||
return true;
|
||||
}
|
||||
else if (PyUtil.hasUnresolvedAncestors(subClass)) {
|
||||
else if (PyUtil.hasUnresolvedAncestors(subClass, context)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -110,7 +110,7 @@ public class PyReplaceExpressionUtil implements PyElementTypes {
|
||||
return replaceSubstringWithDictFormatting(oldExpression, quotes, prefix, suffix, formatValue, newText);
|
||||
}
|
||||
else {
|
||||
final TypeEvalContext context = TypeEvalContext.slow();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
final PyType valueType = context.getType(formatValue);
|
||||
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(oldExpression);
|
||||
final PyType tupleType = builtinCache.getTupleType();
|
||||
|
||||
@@ -188,7 +188,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
|
||||
if (text != null) {
|
||||
candidates.addAll(NameSuggesterUtil.generateNames(text));
|
||||
}
|
||||
final TypeEvalContext context = TypeEvalContext.slow();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated();
|
||||
PyType type = context.getType(expression);
|
||||
if (type != null && type != PyNoneType.INSTANCE) {
|
||||
String typeName = type.getName();
|
||||
|
||||
@@ -50,7 +50,7 @@ public class PythonUnitTestUtil {
|
||||
}
|
||||
|
||||
private static boolean isUnitTestCaseClass(PyClass cls, HashSet<String> testQualifiedNames) {
|
||||
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
|
||||
if (type != null && testQualifiedNames.contains(type.getClassQName())) {
|
||||
return true;
|
||||
}
|
||||
@@ -121,7 +121,7 @@ public class PythonUnitTestUtil {
|
||||
}
|
||||
|
||||
public static boolean isTestCaseClass(@NotNull PyClass cls, Set<String> testQualifiedNames) {
|
||||
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
|
||||
if (type != null) {
|
||||
if (testQualifiedNames.contains(type.getClassQName())) {
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ public class PythonAtTestConfigurationProducer extends
|
||||
|
||||
protected boolean isTestClass(PyClass pyClass) {
|
||||
if (pyClass == null) return false;
|
||||
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
|
||||
if (type != null && "TestBase".equals(type.getName()) && hasTestFunction(pyClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class PyTestUtil {
|
||||
}
|
||||
|
||||
public static boolean isPyTestClass(PyClass pyClass) {
|
||||
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.fastStubOnly(null))) {
|
||||
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
|
||||
if (type != null && PYTHON_TEST_QUALIFIED_CLASSES.contains(type.getClassQName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
myFixture.configureByFile("typeParser/typeParser.py");
|
||||
final PyCollectionType type = (PyCollectionType) PyTypeParser.getTypeByName(myFixture.getFile(), "list of MyObject");
|
||||
assertClassType(type, "list");
|
||||
assertClassType(type.getElementType(TypeEvalContext.fast()), "MyObject");
|
||||
assertClassType(type.getElementType(TypeEvalContext.userInitiated()), "MyObject");
|
||||
}
|
||||
|
||||
public void testDictType() {
|
||||
@@ -41,7 +41,7 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
final PyCollectionType type = (PyCollectionType) PyTypeParser.getTypeByName(myFixture.getFile(), "dict from str to MyObject");
|
||||
assertNotNull(type);
|
||||
assertClassType(type, "dict");
|
||||
final PyType elementType = type.getElementType(TypeEvalContext.fast());
|
||||
final PyType elementType = type.getElementType(TypeEvalContext.userInitiated());
|
||||
assertInstanceOf(elementType, PyTupleType.class);
|
||||
final PyTupleType tupleType = (PyTupleType)elementType;
|
||||
assertEquals(2, tupleType.getElementCount());
|
||||
|
||||
@@ -220,7 +220,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
" return x\n" +
|
||||
"expr = f(1, 2)\n";
|
||||
PyExpression expr = parseExpr(text);
|
||||
PyType t = TypeEvalContext.slow().getType(expr);
|
||||
PyType t = TypeEvalContext.userInitiated().getType(expr);
|
||||
assertTrue(PyTypeChecker.isUnknown(t));
|
||||
doTest("int", text);
|
||||
}
|
||||
@@ -234,7 +234,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
" return foo(x)\n" +
|
||||
"expr = xyzzy(a, b)";
|
||||
PyExpression expr = parseExpr(text);
|
||||
PyType t = TypeEvalContext.slow().getType(expr);
|
||||
PyType t = TypeEvalContext.userInitiated().getType(expr);
|
||||
assertInstanceOf(t, PyTypeReference.class);
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
public void testSOEOnRecursiveCall() {
|
||||
PyExpression expr = parseExpr("def foo(x): return foo(x)\n" +
|
||||
"expr = foo(1)");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType actual = context.getType(expr);
|
||||
assertFalse(actual.isBuiltin(context));
|
||||
}
|
||||
@@ -310,7 +310,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
" return x\n" +
|
||||
"\n" +
|
||||
"expr = f(1)\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType actual = context.getType(expr);
|
||||
assertNotNull(actual);
|
||||
assertEquals("int", actual.getName());
|
||||
@@ -325,7 +325,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
" return x\n" +
|
||||
"\n" +
|
||||
"expr = f(1)\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType actual = context.getType(expr);
|
||||
assertNotNull(actual);
|
||||
assertEquals("int", actual.getName());
|
||||
@@ -335,7 +335,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
public void testYieldType() {
|
||||
PyExpression expr = parseExpr("def f():\n" +
|
||||
" expr = yield 2\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType actual = context.getType(expr);
|
||||
assertNull(actual);
|
||||
}
|
||||
@@ -344,7 +344,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
public void testYieldParensType() {
|
||||
PyExpression expr = parseExpr("def f():\n" +
|
||||
" expr = (yield 2)\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType actual = context.getType(expr);
|
||||
assertNull(actual);
|
||||
}
|
||||
@@ -389,7 +389,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
"\n" +
|
||||
"x = f()\n" +
|
||||
"expr = x.start\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType actual = context.getType(expr);
|
||||
assertNull(actual);
|
||||
}
|
||||
@@ -401,7 +401,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
"\n" +
|
||||
"x = C()\n" +
|
||||
"expr = type(x)\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType type = context.getType(expr);
|
||||
assertInstanceOf(type, PyClassType.class);
|
||||
assertTrue("Got instance type instead of class type", ((PyClassType)type).isDefinition());
|
||||
@@ -413,7 +413,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"expr = type(C)\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType type = context.getType(expr);
|
||||
assertInstanceOf(type, PyClassType.class);
|
||||
assertEquals(type.getName(), "type");
|
||||
@@ -423,7 +423,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
public void testReturnTypeOfTypeForUnknown() {
|
||||
PyExpression expr = parseExpr("def f(x):\n" +
|
||||
" expr = type(x)\n");
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType type = context.getType(expr);
|
||||
assertNull(type);
|
||||
}
|
||||
@@ -453,7 +453,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
// PY-7020
|
||||
public void testListComprehensionType() {
|
||||
final PyExpression expr = parseExpr("expr = [str(x) for x in range(10)]\n");
|
||||
final TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
final PyType type = context.getType(expr);
|
||||
assertNotNull(type);
|
||||
assertInstanceOf(type, PyCollectionType.class);
|
||||
@@ -467,7 +467,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
// PY-7021
|
||||
public void testGeneratorComprehensionType() {
|
||||
final PyExpression expr = parseExpr("expr = (str(x) for x in range(10))\n");
|
||||
final TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
final PyType type = context.getType(expr);
|
||||
assertNotNull(type);
|
||||
assertInstanceOf(type, PyCollectionType.class);
|
||||
@@ -558,7 +558,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
public void testDefaultParameterIgnoreNone() {
|
||||
final PyExpression expr = parseExpr("def f(x=None):\n" +
|
||||
" expr = x\n");
|
||||
final TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
final TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
final PyType type = context.getType(expr);
|
||||
assertNull(type);
|
||||
}
|
||||
@@ -576,7 +576,7 @@ public class PyTypeTest extends PyTestCase {
|
||||
|
||||
private void doTest(final String expectedType, final String text) {
|
||||
PyExpression expr = parseExpr(text);
|
||||
TypeEvalContext context = TypeEvalContext.slow().withTracing();
|
||||
TypeEvalContext context = TypeEvalContext.userInitiated().withTracing();
|
||||
PyType actual = context.getType(expr);
|
||||
PyType expected = PyTypeParser.getTypeByName(expr, expectedType);
|
||||
if (expected != null) {
|
||||
|
||||
@@ -53,7 +53,7 @@ public class PyClassMROTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void assertMRO(@NotNull PyClass cls, @NotNull String... mro) {
|
||||
final List<PyClassLikeType> types = cls.getAncestorTypes(TypeEvalContext.fastStubOnly(null));
|
||||
final List<PyClassLikeType> types = cls.getAncestorTypes(TypeEvalContext.codeInsightFallback());
|
||||
final List<String> classNames = new ArrayList<String>();
|
||||
for (PyClassLikeType type : types) {
|
||||
if (type != null) {
|
||||
|
||||
Reference in New Issue
Block a user