Slow TypeEvalContext for completion, documentation, find usages, quick-fixes

This commit is contained in:
Andrey Vlasovskikh
2013-05-08 19:02:56 +04:00
parent 990006bea2
commit 23ed6bcdaa
9 changed files with 20 additions and 12 deletions
@@ -53,6 +53,11 @@ public class TypeEvalContext {
return myAllowDataFlow || element.getContainingFile() == myOrigin;
}
/**
* 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 slow() {
return new TypeEvalContext(true, true, null);
}
@@ -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.slow();
final PyType type = context.getType(dictConstructor);
if (type != null && type.isBuiltin(context)) {
final PyArgumentList list = dictConstructor.getArgumentList();
@@ -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.slow().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.slow().getType(qual);
if (type instanceof PyClassType) {
cls = ((PyClassType)type).getPyClass();
Property property = cls.findProperty(elementName);
@@ -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.slow().getType((PyNamedParameter)context);
if (type instanceof PyClassType) {
return ((PyClassType)type).getPyClass();
}
@@ -39,7 +39,7 @@ 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 PyType type = TypeEvalContext.slow().getType(qualifier);
if (type == null || type instanceof PyTypeReference) {
final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class);
if (call != null && element == call.getCallee()) {
@@ -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.slow().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.
@@ -81,9 +81,10 @@ public class PyImportReference extends PyReferenceImpl {
}
PyExpression qualifier = myElement.getQualifier();
final TypeEvalContext context = TypeEvalContext.slow();
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);
@@ -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.slow()), "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.slow());
assertInstanceOf(elementType, PyTupleType.class);
final PyTupleType tupleType = (PyTupleType)elementType;
assertEquals(2, tupleType.getElementCount());