PY-14081 Django: QuerySet.as_manager() code editing is really slow

Context cache added
This commit is contained in:
Ilya.Kazakevich
2014-10-14 23:32:38 +04:00
parent 860f5a0b36
commit 9c8ce8b94d
56 changed files with 257 additions and 99 deletions
@@ -36,7 +36,7 @@ public class PyJavaSuperMethodsSearchExecutor implements QueryExecutor<PsiElemen
PyFunction func = queryParameters.getDerivedMethod();
PyClass containingClass = func.getContainingClass();
if (containingClass != null) {
for (PyClassLikeType type : containingClass.getSuperClassTypes(TypeEvalContext.codeInsightFallback())) {
for (PyClassLikeType type : containingClass.getSuperClassTypes(TypeEvalContext.codeInsightFallback(containingClass.getProject()))) {
if (type instanceof PyJavaClassType) {
final PsiClass psiClass = ((PyJavaClassType)type).getPsiClass();
PsiMethod[] methods = psiClass.findMethodsByName(func.getName(), true);
@@ -71,7 +71,7 @@ public class PyResolveContext {
}
public TypeEvalContext getTypeEvalContext() {
return myTypeEvalContext != null ? myTypeEvalContext : TypeEvalContext.codeInsightFallback();
return myTypeEvalContext != null ? myTypeEvalContext : TypeEvalContext.codeInsightFallback(null);
}
@Override
@@ -0,0 +1,53 @@
package com.jetbrains.python.psi.types;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.Nullable;
/**
* A pack of constraints that limit behavior of {@link com.jetbrains.python.psi.types.TypeEvalContext}.
* Any two {@link com.jetbrains.python.psi.types.TypeEvalContext}s may share their cache if their constraints are equal and no PSI changes
* happened between their creation.
* <p/>
* This class created to support hash/equals for context.
*
* @author Ilya.Kazakevich
*/
@SuppressWarnings("PackageVisibleField")
// This is an utility class to be used only in package. Fields are open to type less code
class TypeEvalConstraints {
final boolean myAllowDataFlow;
final boolean myAllowStubToAST;
@Nullable final PsiFile myOrigin;
/**
* @see com.jetbrains.python.psi.types.TypeEvalContext
*/
TypeEvalConstraints(final boolean allowDataFlow, final boolean allowStubToAST, @Nullable final PsiFile origin) {
myAllowDataFlow = allowDataFlow;
myAllowStubToAST = allowStubToAST;
myOrigin = origin;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TypeEvalConstraints)) return false;
TypeEvalConstraints that = (TypeEvalConstraints)o;
if (myAllowDataFlow != that.myAllowDataFlow) return false;
if (myAllowStubToAST != that.myAllowStubToAST) return false;
if (myOrigin != null ? !myOrigin.equals(that.myOrigin) : that.myOrigin != null) return false;
return true;
}
@Override
public int hashCode() {
int result = (myAllowDataFlow ? 1 : 0);
result = 31 * result + (myAllowStubToAST ? 1 : 0);
result = 31 * result + (myOrigin != null ? myOrigin.hashCode() : 0);
return result;
}
}
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.psi.types;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -29,17 +30,25 @@ import java.util.*;
* @author yole
*/
public class TypeEvalContext {
/**
* Contexts are cached here to prevent useless recreations (and cache loss)
*/
@NotNull
private static final TypeEvalContextCache CACHE = new TypeEvalContextCache();
public static class Key {
private static final Key INSTANCE = new Key();
private Key() {}
private Key() {
}
}
private final boolean myAllowDataFlow;
private final boolean myAllowStubToAST;
@NotNull
private final TypeEvalConstraints myConstraints;
private List<String> myTrace;
private String myTraceIndent = "";
@Nullable private final PsiFile myOrigin;
private final Map<PyTypedElement, PyType> myEvaluated = new HashMap<PyTypedElement, PyType>();
private final Map<Callable, PyType> myEvaluatedReturn = new HashMap<Callable, PyType>();
@@ -57,63 +66,70 @@ public class TypeEvalContext {
};
private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, @Nullable PsiFile origin) {
myAllowDataFlow = allowDataFlow;
myAllowStubToAST = allowStubToAST;
myOrigin = origin;
myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, origin);
}
@Override
public String toString() {
return String.format("TypeEvalContext(%b, %b, %s)", myAllowDataFlow, myAllowStubToAST, myOrigin);
return String
.format("TypeEvalContext(%b, %b, %s)", myConstraints.myAllowDataFlow, myConstraints.myAllowStubToAST, myConstraints.myOrigin);
}
public boolean allowDataFlow(PsiElement element) {
return myAllowDataFlow || element.getContainingFile() == myOrigin;
return myConstraints.myAllowDataFlow || element.getContainingFile() == myConstraints.myOrigin;
}
public boolean allowReturnTypes(PsiElement element) {
return myAllowDataFlow || element.getContainingFile() == myOrigin;
return myConstraints.myAllowDataFlow || element.getContainingFile() == myConstraints.myOrigin;
}
public boolean allowLocalUsages(@NotNull PsiElement element) {
return myAllowStubToAST && myAllowDataFlow && element.getContainingFile() == myOrigin;
return myConstraints.myAllowStubToAST && myConstraints.myAllowDataFlow && element.getContainingFile() == myConstraints.myOrigin;
}
/**
* Create the most detailed type evaluation context for user-initiated actions.
*
* <p/>
* Should be used for code completion, go to definition, find usages, refactorings, documentation.
*/
public static TypeEvalContext userInitiated(@Nullable PsiFile origin) {
return new TypeEvalContext(true, true, origin);
public static TypeEvalContext userInitiated(@NotNull final Project project, @Nullable final PsiFile origin) {
return CACHE.getContext(project, new TypeEvalContext(true, true, origin));
}
/**
* 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.
*
* <p/>
* 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);
public static TypeEvalContext codeAnalysis(@NotNull final Project project, @Nullable final PsiFile origin) {
return CACHE.getContext(project, new TypeEvalContext(false, false, origin));
}
/**
* Create the most shallow type evaluation context for code insight purposes when other more detailed contexts are not available.
*
* It's use should be minimized.
* <p/>
* <p/>
*
* @param project pass project here to enable cache. Pass null if you do not have any project.
* <strong>Always</strong> do your best to pass project here: it increases performance!
*/
public static TypeEvalContext codeInsightFallback() {
return new TypeEvalContext(false, false, null);
public static TypeEvalContext codeInsightFallback(@Nullable final Project project) {
final TypeEvalContext anchor = new TypeEvalContext(false, false, null);
if (project != null) {
return CACHE.getContext(project, anchor);
}
return anchor;
}
/**
* Create a type evaluation context for deeper and slower code insight.
*
* <p/>
* 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 static TypeEvalContext deepCodeInsight(@NotNull final Project project) {
return CACHE.getContext(project, new TypeEvalContext(false, true, null));
}
public TypeEvalContext withTracing() {
@@ -137,7 +153,7 @@ public class TypeEvalContext {
public void traceUnindent() {
if (myTrace != null && myTraceIndent.length() >= 2) {
myTraceIndent = myTraceIndent.substring(0, myTraceIndent.length()-2);
myTraceIndent = myTraceIndent.substring(0, myTraceIndent.length() - 2);
}
}
@@ -210,11 +226,19 @@ public class TypeEvalContext {
}
public boolean maySwitchToAST(@NotNull PsiElement element) {
return myAllowStubToAST || myOrigin == element.getContainingFile();
return myConstraints.myAllowStubToAST || myConstraints.myOrigin == element.getContainingFile();
}
@Nullable
public PsiFile getOrigin() {
return myOrigin;
return myConstraints.myOrigin;
}
/**
* @return context constraints (see {@link com.jetbrains.python.psi.types.TypeEvalConstraints}
*/
@NotNull
TypeEvalConstraints getConstraints() {
return myConstraints;
}
}
@@ -0,0 +1,71 @@
package com.jetbrains.python.psi.types;
import com.intellij.openapi.project.Project;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.util.PsiModificationTracker.SERVICE;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* Caches context by their constraints (to prevent context cache loss). Flushes cache every PSI change.
* Class is thread safe.
* See {@link #getContext(com.intellij.openapi.project.Project, TypeEvalContext)}
*
* @author Ilya.Kazakevich
*/
class TypeEvalContextCache {
/**
* Cache itself.
*/
@NotNull
private final Map<TypeEvalConstraints, TypeEvalContext> myCache = new HashMap<TypeEvalConstraints, TypeEvalContext>();
/**
* Current PSI modification count
*/
private long myModificationCount = -1;
/**
* Lock to sync
*/
@NotNull
private final Object myLock = new Object();
/**
* Returns context from cache (if exist) or returns the one you provided (and puts it into cache).
* To use this method, do the following:
* <ol>
* <li>Instantiate {@link com.jetbrains.python.psi.types.TypeEvalContext} you want to use</li>
* <li>Pass its instance here as argument</li>
* <li>Use result</li>
* </ol>
*
* @param project project is required for caching engine
* @param standard context you want to use. Just instantiate it and pass here.
* @return context from cache (the one equals by constraints to yours or the one you provided)
*/
@NotNull
TypeEvalContext getContext(@NotNull final Project project, @NotNull final TypeEvalContext standard) {
final PsiModificationTracker tracker = SERVICE.getInstance(project);
synchronized (myLock) {
final long currentCount = tracker.getOutOfCodeBlockModificationCount();
if (currentCount == myModificationCount) {
// Cache is valid, use it
final TypeEvalContext valueFromCache = myCache.get(standard.getConstraints());
if (valueFromCache != null) {
// We have element in cache, return it
return valueFromCache;
}
}
else {
// Cache is invalid, flush it and store current count
myCache.clear();
myModificationCount = currentCount;
}
// We do not have value in cache (or cache is invalid), put it
myCache.put(standard.getConstraints(), standard);
return standard;
}
}
}
@@ -54,7 +54,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
public PyArgumentList findElementForParameterInfo(@NotNull final CreateParameterInfoContext context) {
PyArgumentList arglist = findArgumentList(context);
if (arglist != null) {
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(arglist.getContainingFile());
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(arglist.getProject(), arglist.getContainingFile());
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(typeEvalContext);
CallArgumentsMapping result = arglist.analyzeCall(resolveContext);
if (result.getMarkedCallee() != null) {
@@ -130,7 +130,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
final PyArgumentList argList = prevResult.getArgumentList();
if (!argList.isValid()) return;
// really we need to redo analysis every UI update; findElementForParameterInfo isn't called while typing
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(argList.getContainingFile());
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(argList.getProject(), argList.getContainingFile());
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(typeEvalContext);
final CallArgumentsMapping argumentsMapping = argList.analyzeCall(resolveContext);
final PyMarkedCallee marked = argumentsMapping.getMarkedCallee();
@@ -129,7 +129,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor {
if (callee == null) return;
final String name = callee.getText();
if ("dict".equals(name)) {
final TypeEvalContext context = TypeEvalContext.userInitiated(callee.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(callee.getProject(), callee.getContainingFile());
final PyType type = context.getType(dictConstructor);
if (type != null && type.isBuiltin()) {
final PyArgumentList list = dictConstructor.getArgumentList();
@@ -255,7 +255,7 @@ public class ConvertFormatOperatorToMethodIntention extends BaseIntentionAction
final PyExpression rhs = PyPsiUtils.flattenParens(rightExpression);
if (rhs == null) return;
final String paramText = sure(rhs).getText();
final TypeEvalContext context = TypeEvalContext.userInitiated(file);
final TypeEvalContext context = TypeEvalContext.userInitiated(file.getProject(), file);
final PyType rhsType = context.getType(rhs);
String prefix = "";
if (PyTypeChecker.match(PyBuiltinCache.getInstance(rhs).getObjectType("unicode"), rhsType, context)) {
@@ -160,7 +160,7 @@ public class ImportFromToImportIntention implements IntentionAction {
PyReferenceExpression ref = import_element.getImportReferenceExpression();
if (ref != null && ref.isValid()) {
PsiElement target = ref.getReference().resolve();
final TypeEvalContext context = TypeEvalContext.codeAnalysis(file);
final TypeEvalContext context = TypeEvalContext.codeAnalysis(file.getProject(), file);
if (target instanceof PyExpression && context.getType((PyExpression)target) instanceof PyModuleType) {
return false;
}
@@ -56,7 +56,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.codeAnalysis(file);
final TypeEvalContext context = TypeEvalContext.codeAnalysis(file.getProject(), file);
PyType type = context.getType(expression);
if (type != null && type.isBuiltin()) {
PyExpression[] argumentList = expression.getArguments();
@@ -82,9 +82,9 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction
}
if (expression instanceof PyStringLiteralExpression)
continue;
final PyType type = TypeEvalContext.codeAnalysis(file).getType(expression);
final PyType type = TypeEvalContext.codeAnalysis(file.getProject(), file).getType(expression);
final boolean isStringReference = PyTypeChecker.match(cache.getStringType(LanguageLevel.forElement(expression)),
type, TypeEvalContext.codeAnalysis(file)) && type != null;
type, TypeEvalContext.codeAnalysis(file.getProject(), file)) && type != null;
if (!isStringReference) {
return false;
}
@@ -136,7 +136,7 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction
List<String> parameters = new ArrayList<String>();
Pair<String, String> quotes = Pair.create("\"", "\"");
boolean quotesDetected = false;
final TypeEvalContext context = TypeEvalContext.userInitiated(file);
final TypeEvalContext context = TypeEvalContext.userInitiated(file.getProject(), file);
int paramCount = 0;
boolean isUnicode = false;
final PyClassTypeImpl unicodeType = PyBuiltinCache.getInstance(element).getObjectType("unicode");
@@ -75,7 +75,7 @@ public class TypeAssertionIntention implements IntentionAction {
(reference != null && reference.resolve() == null)) {
return false;
}
final PyType type = TypeEvalContext.codeAnalysis(file).getType(problemElement);
final PyType type = TypeEvalContext.codeAnalysis(file.getProject(), file).getType(problemElement);
return type == null;
}
@@ -180,7 +180,7 @@ public abstract class TypeIntention implements IntentionAction {
}
protected PyResolveContext getResolveContext(@NotNull PsiElement origin) {
return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(origin.getContainingFile()));
return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(origin.getProject(), origin.getContainingFile()));
}
public boolean startInWriteAction() {
@@ -84,7 +84,7 @@ public class PyIterableVariableMacro extends Macro {
@NotNull
protected List<PsiNamedElement> getIterableElements(@NotNull PsiElement element) {
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(element.getContainingFile());
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile());
final List<PsiNamedElement> components = new ArrayList<PsiNamedElement>();
for (PsiNamedElement namedElement : getVisibleNamedElements(element)) {
if (namedElement instanceof PyTypedElement) {
@@ -36,7 +36,7 @@ public class PyMethodMember extends PsiElementMemberChooserObject implements Cla
private final String myFullName;
private static String buildNameFor(final PyElement element) {
if (element instanceof PyFunction) {
final TypeEvalContext context = TypeEvalContext.userInitiated(element.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile());
final List<PyParameter> parameters = PyUtil.getParameters((PyFunction)element, context);
return element.getName() + "(" + StringUtil.join(parameters, new Function<PyParameter, String>() {
@Override
@@ -193,7 +193,7 @@ public class PyOverrideImplementUtil {
if (anno != null) {
pyFunctionBuilder.annotation(anno.getText());
}
final TypeEvalContext context = TypeEvalContext.userInitiated(baseFunction.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(baseFunction.getProject(), baseFunction.getContainingFile());
final List<PyParameter> baseParams = PyUtil.getParameters(baseFunction, context);
for (PyParameter parameter : baseParams) {
pyFunctionBuilder.parameter(parameter.getText());
@@ -159,7 +159,8 @@ public class PyUserSkeletonsUtil {
assert owner != element;
final PsiElement originalOwner = getUserSkeleton(owner, skeletonFile);
if (originalOwner instanceof PyClass) {
final PyType type = TypeEvalContext.codeInsightFallback().getType((PyClass)originalOwner);
final PyClass classOwner = (PyClass)originalOwner;
final PyType type = TypeEvalContext.codeInsightFallback(classOwner.getProject()).getType(classOwner);
if (type instanceof PyClassLikeType) {
final PyClassLikeType classType = (PyClassLikeType)type;
final PyClassLikeType instanceType = classType.toInstance();
@@ -132,7 +132,7 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase<PsiEleme
for (PyImportElement element : elements) {
final PyReferenceExpression referenceExpression = element.getImportReferenceExpression();
if (referenceExpression == null) continue;
final PyType type = TypeEvalContext.userInitiated(CompletionUtil.getOriginalOrSelf(file)).getType(referenceExpression);
final PyType type = TypeEvalContext.userInitiated(file.getProject(), CompletionUtil.getOriginalOrSelf(file)).getType(referenceExpression);
if (type instanceof PyClassType) {
variants.add(((PyClassType)type).getPyClass());
}
@@ -84,7 +84,7 @@ class PyDocumentationBuilder {
PsiElement outer = null;
boolean is_property = false;
String accessor_kind = "None";
final TypeEvalContext context = TypeEvalContext.userInitiated(myElement.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(myElement.getProject(), myElement.getContainingFile());
if (myOriginalElement != null) {
String elementName = myOriginalElement.getText();
if (PyUtil.isPythonIdentifier(elementName)) {
@@ -152,7 +152,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
ChainIterable<String> cat = new ChainIterable<String>();
final String name = fun.getName();
cat.addItem("def ").addWith(func_name_wrapper, $(name));
final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getProject(), fun.getContainingFile());
final List<PyParameter> parameters = PyUtil.getParameters(fun, context);
final String paramStr = "(" +
StringUtil.join(parameters,
@@ -195,12 +195,12 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
}
static String describeType(@NotNull PyTypedElement element) {
final TypeEvalContext context = TypeEvalContext.userInitiated(element.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile());
return String.format("Inferred type: %s", getTypeName(context.getType(element), context));
}
public static void getTypeDescription(@NotNull PyFunction fun, ChainIterable<String> body) {
final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(fun.getProject(), fun.getContainingFile());
PyTypeModelBuilder builder = new PyTypeModelBuilder(context);
builder.build(context.getType(fun), true).toBodyWithLinks(body, fun);
}
@@ -524,7 +524,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
@Nullable
private static PyClass inferClassOfParameter(PsiElement context) {
if (context instanceof PyNamedParameter) {
final PyType type = TypeEvalContext.userInitiated(context.getContainingFile()).getType((PyNamedParameter)context);
final PyType type = TypeEvalContext.userInitiated(context.getProject(), context.getContainingFile()).getType((PyNamedParameter)context);
if (type instanceof PyClassType) {
return ((PyClassType)type).getPyClass();
}
@@ -594,7 +594,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
//TODO: this code duplicates PyDocstringGenerator in some parts
final StringBuilder builder = new StringBuilder(offset);
final TypeEvalContext context = TypeEvalContext.userInitiated(function.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(function.getProject(), function.getContainingFile());
PySignature signature = PySignatureCacheManager.getInstance(function.getProject()).findSignature(function);
final PyDecoratorList decoratorList = function.getDecoratorList();
final PyDecorator classMethod = decoratorList == null ? null : decoratorList.findDecorator(PyNames.CLASSMETHOD);
@@ -53,7 +53,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx {
if (element instanceof PyQualifiedExpression) {
final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier();
if (qualifier != null) {
final TypeEvalContext context = TypeEvalContext.userInitiated(element.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile());
final PyType type = context.getType(qualifier);
if (type == null) {
final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class);
@@ -302,7 +302,7 @@ public class PyCompatibilityInspection extends PyInspection {
public void visitPyReferenceExpression(PyReferenceExpression node) {
super.visitPyElement(node);
if (shouldBeCompatibleWithPy3()) {
final TypeEvalContext context = TypeEvalContext.codeAnalysis(node.getContainingFile());
final TypeEvalContext context = TypeEvalContext.codeAnalysis(node.getProject(), node.getContainingFile());
final String nodeText = node.getText();
if (nodeText.endsWith("iteritems") || nodeText.endsWith("iterkeys") || nodeText.endsWith("itervalues")) {
final PyExpression qualifier = node.getQualifier();
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.types.TypeEvalContext;
@@ -45,7 +46,8 @@ public abstract class PyInspectionVisitor extends PyElementVisitor {
synchronized (INSPECTION_TYPE_EVAL_CONTEXT) {
context = session.getUserData(INSPECTION_TYPE_EVAL_CONTEXT);
if (context == null) {
context = TypeEvalContext.codeAnalysis(session.getFile());
PsiFile file = session.getFile();
context = TypeEvalContext.codeAnalysis(file.getProject(), file);
session.putUserData(INSPECTION_TYPE_EVAL_CONTEXT, context);
}
}
@@ -118,7 +118,7 @@ public class AddFieldQuickFix implements LocalQuickFix {
if (element instanceof PyQualifiedExpression) {
final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier();
if (qualifier == null) return null;
final PyType type = TypeEvalContext.userInitiated(element.getContainingFile()).getType(qualifier);
final PyType type = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).getType(qualifier);
return type instanceof PyClassType ? (PyClassType)type : null;
}
final PyClass aClass = PsiTreeUtil.getParentOfType(element, PyClass.class);
@@ -78,7 +78,7 @@ public class AddFunctionQuickFix implements LocalQuickFix {
if (!(problemElement instanceof PyQualifiedExpression)) return;
final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
if (qualifier == null) return;
final PyType type = TypeEvalContext.userInitiated(problemElement.getContainingFile()).getType(qualifier);
final PyType type = TypeEvalContext.userInitiated(problemElement.getProject(), problemElement.getContainingFile()).getType(qualifier);
if (!(type instanceof PyModuleType)) return;
final PyFile file = ((PyModuleType)type).getModule();
sure(file);
@@ -96,7 +96,7 @@ public class AddMethodQuickFix implements LocalQuickFix {
boolean madeInstance = false;
if (callByClass) {
if (args.length > 0) {
PyType firstArgType = TypeEvalContext.userInitiated(cls.getContainingFile()).getType(args[0]);
PyType firstArgType = TypeEvalContext.userInitiated(cls.getProject(), cls.getContainingFile()).getType(args[0]);
if (firstArgType instanceof PyClassType && ((PyClassType)firstArgType).getPyClass().isSubclass(cls)) {
// class, first arg ok: instance method
builder.parameter("self"); // NOTE: might use a name other than 'self', according to code style.
@@ -151,7 +151,7 @@ public class AddMethodQuickFix implements LocalQuickFix {
if ((problemElement instanceof PyQualifiedExpression)) {
final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
if (qualifier == null) return null;
final PyType type = TypeEvalContext.userInitiated(problemElement.getContainingFile()).getType(qualifier);
final PyType type = TypeEvalContext.userInitiated(problemElement.getProject(), problemElement.getContainingFile()).getType(qualifier);
return type instanceof PyClassType ? (PyClassType)type : null;
}
final PyClass pyClass = PsiTreeUtil.getParentOfType(problemElement, PyClass.class);
@@ -65,7 +65,7 @@ public class PyAddSpecifierToFormatQuickFix implements LocalQuickFix {
final Document document = FileDocumentManager.getInstance().getDocument(file.getVirtualFile());
if (document == null) return;
final int offset = element.getTextOffset();
final TypeEvalContext context = TypeEvalContext.userInitiated(file);
final TypeEvalContext context = TypeEvalContext.userInitiated(file.getProject(), file);
final PyClassType strType = PyBuiltinCache.getInstance(element).getStrType();
final PyClassType floatType = PyBuiltinCache.getInstance(element).getFloatType();
@@ -50,7 +50,7 @@ public class PyCreatePropertyQuickFix implements LocalQuickFix {
if (element instanceof PyQualifiedExpression) {
final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier();
if (qualifier != null) {
final PyType type = TypeEvalContext.codeAnalysis(element.getContainingFile()).getType(qualifier);
final PyType type = TypeEvalContext.codeAnalysis(element.getProject(), element.getContainingFile()).getType(qualifier);
if (type instanceof PyClassType) {
final PyClass cls = ((PyClassType)type).getPyClass();
final String propertyName = ((PyQualifiedExpression)element).getName();
@@ -108,7 +108,7 @@ public class PythonPatterns extends PlatformPatterns {
// TODO is it better or worse to allow implicits here?
PyResolveContext context = PyResolveContext.noImplicits()
.withTypeEvalContext(TypeEvalContext.codeAnalysis(expression.getContainingFile()));
.withTypeEvalContext(TypeEvalContext.codeAnalysis(expression.getProject(), expression.getContainingFile()));
PyCallExpression.PyMarkedCallee callee = call.resolveCallee(context);
return callee != null ? callee.getCallable() : null;
@@ -1209,7 +1209,7 @@ public class PyUtil {
if (isBaseException(pyClass.getQualifiedName())) {
return true;
}
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback(pyClass.getProject()))) {
if (type != null && isBaseException(type.getClassQName())) {
return true;
}
@@ -148,7 +148,7 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
List<PsiReference> referencesList = new ArrayList<PsiReference>();
final PsiFile file = element.getContainingFile();
final PyResolveContext resolveContext = file != null ?
PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(file)) :
PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(file.getProject(), file)) :
PyResolveContext.defaultContext();
while (element != null) {
addReferences(offset, element, referencesList, resolveContext);
@@ -201,7 +201,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
@NotNull
@Override
public List<PyClass> getAncestorClasses() {
return getAncestorClasses(TypeEvalContext.codeInsightFallback());
return getAncestorClasses(TypeEvalContext.codeInsightFallback(getProject()));
}
@NotNull
@@ -231,7 +231,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
if (superClassQName.equals(getQualifiedName())) {
return true;
}
for (PyClassLikeType type : getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
for (PyClassLikeType type : getAncestorTypes(TypeEvalContext.codeInsightFallback(getProject()))) {
if (type != null && superClassQName.equals(type.getClassQName())) {
return true;
}
@@ -279,7 +279,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
@NotNull
public PyClass[] getSuperClasses() {
final List<PyClassLikeType> superTypes = getSuperClassTypes(TypeEvalContext.codeInsightFallback());
final List<PyClassLikeType> superTypes = getSuperClassTypes(TypeEvalContext.codeInsightFallback(getProject()));
if (superTypes.isEmpty()) {
return EMPTY_ARRAY;
}
@@ -1033,7 +1033,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
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.codeInsightFallback())) {
for (PyClassLikeType type : getOldStyleAncestorTypes(TypeEvalContext.codeInsightFallback(getProject()))) {
if (type == null) {
// unknown, assume new-style class
return true;
@@ -66,7 +66,7 @@ public class KeywordArgumentCompletionUtil {
visited.add(def);
boolean needSelf = def.getContainingClass() != null && def.getModifier() != PyFunction.Modifier.STATICMETHOD;
final KwArgParameterCollector collector = new KwArgParameterCollector(needSelf, ret);
final TypeEvalContext context = TypeEvalContext.userInitiated(def.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(def.getProject(), def.getContainingFile());
final List<PyParameter> parameters = PyUtil.getParameters(def, context);
for (PyParameter parameter : parameters) {
parameter.accept(collector);
@@ -97,7 +97,7 @@ public class PyImportReference extends PyReferenceImpl {
}
PyExpression qualifier = myElement.getQualifier();
final TypeEvalContext context = TypeEvalContext.userInitiated(CompletionUtil.getOriginalOrSelf(myElement).getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(myElement.getProject(), CompletionUtil.getOriginalOrSelf(myElement).getContainingFile());
if (qualifier != null) {
// qualifier's type must be module, it should know how to complete
PyType type = context.getType(qualifier);
@@ -260,7 +260,7 @@ public class PyQualifiedReference extends PyReferenceImpl {
}
final PyQualifiedExpression element = CompletionUtil.getOriginalOrSelf(myElement);
PyType qualifierType = TypeEvalContext.userInitiated(element.getContainingFile()).getType(qualifier);
PyType qualifierType = TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).getType(qualifier);
ProcessingContext ctx = new ProcessingContext();
final Set<String> namesAlready = new HashSet<String>();
ctx.put(PyType.CTX_NAMES, namesAlready);
@@ -415,7 +415,7 @@ public class PyQualifiedReference extends PyReferenceImpl {
if (containingFile instanceof StubBasedPsiElement) {
assert ((StubBasedPsiElement)containingFile).getStub() == null : "Stub origin for type eval context in isReferenceTo()";
}
final TypeEvalContext context = TypeEvalContext.codeAnalysis(containingFile);
final TypeEvalContext context = TypeEvalContext.codeAnalysis(containingFile.getProject(), containingFile);
resolveContext = resolveContext.withTypeEvalContext(context);
}
if (element instanceof PyFunction && Comparing.equal(referencedName, ((PyFunction)element).getName()) &&
@@ -17,6 +17,7 @@ package com.jetbrains.python.psi.resolve;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
@@ -65,8 +66,9 @@ public class CompletionVariantsProcessor extends VariantsProcessor {
object instanceof PyFunction && ((PyFunction)object).getProperty() == null &&
!PyUtil.hasCustomDecorators((PyFunction)object) &&
!isSingleArgDecoratorCall(myContext, (PyFunction)object)) {
final Project project = ((PyFunction)object).getProject();
item = item.withInsertHandler(PyFunctionInsertHandler.INSTANCE);
final TypeEvalContext context = TypeEvalContext.userInitiated(myContext != null ? myContext.getContainingFile() : null);
final TypeEvalContext context = TypeEvalContext.userInitiated(project, myContext != null ? myContext.getContainingFile() : null);
final List<PyParameter> parameters = PyUtil.getParameters((PyFunction)object, context);
final String params = StringUtil.join(parameters, new Function<PyParameter, String>() {
@Override
@@ -82,7 +82,7 @@ public class PyCallableTypeImpl implements PyCallableType {
@Nullable
@Override
public String getName() {
final TypeEvalContext context = TypeEvalContext.codeInsightFallback();
final TypeEvalContext context = TypeEvalContext.codeInsightFallback(null);
return String.format("(%s) -> %s",
myParameters != null ?
StringUtil.join(myParameters,
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiInvalidElementAccessException;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
@@ -410,9 +411,11 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType {
boolean suppressParentheses = context.get(CTX_SUPPRESS_PARENTHESES) != null;
addOwnClassMembers(location, namesAlready, suppressParentheses, ret);
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(location != null ?
CompletionUtil.getOriginalOrSelf(location).getContainingFile() :
null);
PsiFile origin = (location != null) ?
CompletionUtil.getOriginalOrSelf(location)
.getContainingFile() :
null;
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(myClass.getProject(), origin);
addInheritedMembers(prefix, location, namesAlready, context, ret, typeEvalContext);
// from providers
@@ -55,7 +55,7 @@ public class PyCollectionTypeImpl extends PyClassTypeImpl implements PyCollectio
PyCollectionType type = (PyCollectionType)o;
final TypeEvalContext context = TypeEvalContext.codeInsightFallback();
final TypeEvalContext context = TypeEvalContext.codeInsightFallback(myClass.getProject());
if (myElementType != null ? !myElementType.equals(type.getElementType(context)) : type.getElementType(context) != null) return false;
return true;
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.psi.types;
import com.intellij.openapi.project.Project;
import com.jetbrains.python.PyNames;
import org.jetbrains.annotations.NotNull;
@@ -49,7 +50,7 @@ public class PyDynamicallyEvaluatedType extends PyUnionType {
@Override
public String getName() {
PyType res = excludeNull(TypeEvalContext.codeInsightFallback());
PyType res = excludeNull(TypeEvalContext.codeInsightFallback(null));
return res != null ? res.getName() : PyNames.UNKNOWN_TYPE;
}
}
@@ -88,7 +88,7 @@ public class PyFunctionType implements PyCallableType {
@Override
public Object[] getCompletionVariants(String completionPrefix, PsiElement location, ProcessingContext context) {
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(location.getContainingFile());
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(location.getProject(), location.getContainingFile());
final PyClassType delegate;
if (location instanceof PyReferenceExpression) {
delegate = selectFakeType(((PyReferenceExpression)location).getQualifier(), typeEvalContext);
@@ -343,7 +343,7 @@ public class PyTypeParser {
if (file instanceof PyFile) {
final PyFile pyFile = (PyFile)file;
final TypeEvalContext context = TypeEvalContext.codeInsightFallback();
final TypeEvalContext context = TypeEvalContext.codeInsightFallback(file.getProject());
final Map<TextRange, PyType> types = new HashMap<TextRange, PyType>();
final Map<PyType, TextRange> fullRanges = new HashMap<PyType, TextRange>();
final Map<PyType, PyImportElement> imports = new HashMap<PyType, PyImportElement>();
@@ -152,7 +152,7 @@ public class PyReplaceExpressionUtil implements PyElementTypes {
return replaceSubstringWithDictFormatting(oldExpression, quotes, prefix, suffix, formatValue, newText);
}
else {
final TypeEvalContext context = TypeEvalContext.userInitiated(oldExpression.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(oldExpression.getProject(), oldExpression.getContainingFile());
final PyType valueType = context.getType(formatValue);
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(oldExpression);
final PyType tupleType = builtinCache.getTupleType();
@@ -122,7 +122,7 @@ class MethodsManager extends MembersManager<PyFunction> {
// TODO: Copy/Paste with PyClass.getMeta..
private static boolean addMetaAbcIfNeeded(@NotNull final PyClass aClass) {
final PsiFile file = aClass.getContainingFile();
final PyType type = aClass.getMetaClassType(TypeEvalContext.userInitiated(file));
final PyType type = aClass.getMetaClassType(TypeEvalContext.userInitiated(aClass.getProject(), file));
if (type != null) {
return false; //User already has metaclass. He probably knows about metaclasses, so we should not add ABCMeta
}
@@ -45,7 +45,7 @@ class PyAncestorsUtils extends NotNullPredicate<PyClass> {
*/
@NotNull
static Collection<PyClass> getAncestorsUnderUserControl(@NotNull final PyClass pyClass) {
final List<PyClass> allAncestors = pyClass.getAncestorClasses(TypeEvalContext.userInitiated(pyClass.getContainingFile()));
final List<PyClass> allAncestors = pyClass.getAncestorClasses(TypeEvalContext.userInitiated(pyClass.getProject(), pyClass.getContainingFile()));
return Collections2.filter(allAncestors, new PyAncestorsUtils(PyUtil.getSourceRoots(pyClass)));
}
@@ -205,7 +205,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
if (text != null) {
candidates.addAll(NameSuggesterUtil.generateNames(text));
}
final TypeEvalContext context = TypeEvalContext.userInitiated(expression.getContainingFile());
final TypeEvalContext context = TypeEvalContext.userInitiated(expression.getProject(), expression.getContainingFile());
PyType type = context.getType(expression);
if (type != null && type != PyNoneType.INSTANCE) {
String typeName = type.getName();
@@ -82,7 +82,7 @@ public class PythonUnitTestUtil {
if (expression.getText().equals("TestCase")) return true;
}
}
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback(cls.getProject()))) {
if (type != null && testQualifiedNames.contains(type.getClassQName())) {
return true;
}
@@ -153,7 +153,7 @@ public class PythonUnitTestUtil {
}
public static boolean isTestCaseClass(@NotNull PyClass cls, Set<String> testQualifiedNames) {
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
for (PyClassLikeType type : cls.getAncestorTypes(TypeEvalContext.codeInsightFallback(cls.getProject()))) {
if (type != null) {
if (testQualifiedNames.contains(type.getClassQName())) {
return true;
@@ -51,7 +51,7 @@ public class PythonAtTestConfigurationProducer extends
@Override
protected boolean isTestClass(@NotNull final PyClass pyClass, @Nullable final AbstractPythonTestRunConfiguration configuration) {
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback(pyClass.getProject()))) {
if (type != null && "TestBase".equals(type.getName()) && hasTestFunction(pyClass)) {
return true;
}
@@ -71,7 +71,7 @@ public class PyTestUtil {
}
public static boolean isPyTestClass(PyClass pyClass) {
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback())) {
for (PyClassLikeType type : pyClass.getAncestorTypes(TypeEvalContext.codeInsightFallback(pyClass.getProject()))) {
if (type != null && PYTHON_TEST_QUALIFIED_CLASSES.contains(type.getClassQName())) {
return true;
}
@@ -126,7 +126,8 @@ public class PythonSkeletonsTest extends PyEnvTestCase {
myFixture.configureByText(PythonFileType.INSTANCE,
"expr = slice(1, 2).start\n");
final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getFile());
PsiFile file = myFixture.getFile();
final TypeEvalContext context = TypeEvalContext.codeAnalysis(file.getProject(), file);
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
@@ -95,7 +95,7 @@ public class PyClassicPropertyTest extends PyTestCase {
accessor = p.getGetter();
assertFalse(accessor.isDefined());
final PyType codeInsightType = p.getType(TypeEvalContext.codeInsightFallback());
final PyType codeInsightType = p.getType(TypeEvalContext.codeInsightFallback(myClass.getProject()));
assertNull(codeInsightType);
accessor = p.getSetter();
@@ -422,7 +422,7 @@ public class PyStubsTest extends PyTestCase {
final PyClass d = file.findTopLevelClass("D");
assertNotNull(d);
assertNull(d.getMetaClassExpression());
assertNotNull(d.getMetaClassType(TypeEvalContext.codeInsightFallback()));
assertNotNull(d.getMetaClassType(TypeEvalContext.codeInsightFallback(c.getProject())));
assertNotParsed(file);
}
}
@@ -68,7 +68,7 @@ public class PyTypeParserTest extends PyTestCase {
}
private TypeEvalContext getTypeEvalContext() {
return TypeEvalContext.userInitiated(myFixture.getFile());
return TypeEvalContext.userInitiated(myFixture.getProject(), myFixture.getFile());
}
public void testUnionType() {
@@ -188,7 +188,7 @@ public class PyTypeParserTest extends PyTestCase {
final PyCollectionType collectionType = (PyCollectionType)type;
assertNotNull(collectionType);
assertEquals("list", collectionType.getName());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback(null));
assertInstanceOf(elementType, PyUnionType.class);
}
@@ -209,7 +209,7 @@ public class PyTypeParserTest extends PyTestCase {
final PyCollectionType collectionType = (PyCollectionType)type;
assertNotNull(collectionType);
assertEquals("list", collectionType.getName());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback(null));
assertNotNull(elementType);
assertEquals("int", elementType.getName());
}
@@ -221,7 +221,7 @@ public class PyTypeParserTest extends PyTestCase {
final PyCollectionType collectionType = (PyCollectionType)type;
assertNotNull(collectionType);
assertEquals("dict", collectionType.getName());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback());
final PyType elementType = collectionType.getElementType(TypeEvalContext.codeInsightFallback(null));
assertNotNull(elementType);
assertInstanceOf(elementType, PyTupleType.class);
final PyTupleType tupleType = (PyTupleType)elementType;
@@ -291,7 +291,7 @@ public class PyTypeParserTest extends PyTestCase {
myFixture.configureByFile("typeParser/typeParser.py");
final PsiFile file = myFixture.getFile();
final PyType type = PyTypeParser.getTypeByName(file, text);
TypeEvalContext context = TypeEvalContext.userInitiated(file).withTracing();
TypeEvalContext context = TypeEvalContext.userInitiated(file.getProject(), file).withTracing();
final String actualType = PythonDocumentationProvider.getTypeName(type, context);
assertEquals(expectedType, actualType);
}
@@ -874,7 +874,7 @@ public class PyTypeTest extends PyTestCase {
}
private static TypeEvalContext getTypeEvalContext(@NotNull PyExpression element) {
return TypeEvalContext.userInitiated(element.getContainingFile()).withTracing();
return TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).withTracing();
}
private PyExpression parseExpr(String text) {
@@ -253,8 +253,8 @@ public class PyTypingTest extends PyTestCase {
myFixture.copyDirectoryToProject("typing", "");
myFixture.configureByText(PythonFileType.INSTANCE, text);
final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
final TypeEvalContext codeAnalysis = TypeEvalContext.codeAnalysis(expr.getContainingFile());
final TypeEvalContext userInitiated = TypeEvalContext.userInitiated(expr.getContainingFile()).withTracing();
final TypeEvalContext codeAnalysis = TypeEvalContext.codeAnalysis(expr.getProject(),expr.getContainingFile());
final TypeEvalContext userInitiated = TypeEvalContext.userInitiated(expr.getProject(), expr.getContainingFile()).withTracing();
assertType(expectedType, expr, codeAnalysis, "code analysis");
assertType(expectedType, expr, userInitiated, "user initiated");
}
@@ -72,7 +72,7 @@ public class PyClassMROTest extends PyTestCase {
}
public void assertMRO(@NotNull PyClass cls, @NotNull String... mro) {
final List<PyClassLikeType> types = cls.getAncestorTypes(TypeEvalContext.codeInsightFallback());
final List<PyClassLikeType> types = cls.getAncestorTypes(TypeEvalContext.codeInsightFallback(cls.getProject()));
final List<String> classNames = new ArrayList<String>();
for (PyClassLikeType type : types) {
if (type != null) {