implicit resolve works also for instance attributes (PY-4292)

This commit is contained in:
Dmitry Jemerov
2011-08-12 18:54:19 +02:00
parent 9845ac2a11
commit a6f9e823e7
9 changed files with 88 additions and 16 deletions
@@ -66,6 +66,7 @@
<stubIndex implementation="com.jetbrains.python.psi.stubs.PyFunctionNameIndex"/>
<stubIndex implementation="com.jetbrains.python.psi.stubs.PySuperClassIndex"/>
<stubIndex implementation="com.jetbrains.python.psi.stubs.PyVariableNameIndex"/>
<stubIndex implementation="com.jetbrains.python.psi.stubs.PyInstanceAttributeIndex"/>
<fileTypeIndentOptionsProvider implementation="com.jetbrains.python.formatter.PyIndentOptionsProvider"/>
@@ -21,6 +21,7 @@ import com.jetbrains.python.psi.patterns.SyntaxMatchers;
import com.jetbrains.python.psi.resolve.*;
import com.jetbrains.python.psi.stubs.PyClassNameIndexInsensitive;
import com.jetbrains.python.psi.stubs.PyFunctionNameIndex;
import com.jetbrains.python.psi.stubs.PyInstanceAttributeIndex;
import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -80,9 +81,19 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl {
}
PyFunction pyFunction = (PyFunction) function;
if (pyFunction.getContainingClass() != null) {
ret.add(new ImplicitResolveResult(pyFunction, getFunctionRate(pyFunction)));
ret.add(new ImplicitResolveResult(pyFunction, getImplicitResultRate(pyFunction)));
}
}
final Collection attributes = PyInstanceAttributeIndex.find(referencedName, myElement.getProject());
for (Object attribute : attributes) {
if (!(attribute instanceof PyTargetExpression)) {
FileBasedIndex.getInstance().scheduleRebuild(StubUpdatingIndex.INDEX_ID,
new Throwable("found non-target expression object " + attribute + " in target expression list"));
break;
}
ret.add(new ImplicitResolveResult((PyTargetExpression) attribute, getImplicitResultRate((PyTargetExpression)attribute)));
}
}
// special case of __doc__
if ("__doc__".equals(referencedName)) {
@@ -91,17 +102,23 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl {
return ret;
}
private int getFunctionRate(PyFunction pyFunction) {
private int getImplicitResultRate(PyElement target) {
int rate = RatedResolveResult.RATE_LOW;
if (pyFunction.getContainingFile() == myElement.getContainingFile()) {
if (target.getContainingFile() == myElement.getContainingFile()) {
rate += 200;
}
else {
final VirtualFile vFile = pyFunction.getContainingFile().getVirtualFile();
final VirtualFile vFile = target.getContainingFile().getVirtualFile();
if (vFile != null && ProjectScope.getProjectScope(myElement.getProject()).contains(vFile)) {
rate += 80;
}
}
if (myElement.getParent() instanceof PyCallExpression) {
if (target instanceof PyFunction) rate += 50;
}
else {
if (!(target instanceof PyFunction)) rate += 50;
}
return rate;
}
@@ -14,9 +14,7 @@ import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyQualifiedName;
import com.jetbrains.python.psi.impl.PyTargetExpressionImpl;
import com.jetbrains.python.psi.stubs.PyFileStub;
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
import com.jetbrains.python.psi.stubs.PyVariableNameIndex;
import com.jetbrains.python.psi.stubs.*;
import java.io.IOException;
@@ -121,14 +119,22 @@ public class PyTargetExpressionElementType extends PyStubElementType<PyTargetExp
@Override
public void indexStub(PyTargetExpressionStub stub, IndexSink sink) {
if (stub.getParentStub() instanceof PyFileStub) {
String name = stub.getName();
if (name != null && PyUtil.getInitialUnderscores(name) == 0) {
String name = stub.getName();
if (name != null && PyUtil.getInitialUnderscores(name) == 0) {
if (stub.getParentStub() instanceof PyFileStub) {
sink.occurrence(PyVariableNameIndex.KEY, name);
}
else if (isInstanceAttributeStub(stub)) {
sink.occurrence(PyInstanceAttributeIndex.KEY, name);
}
}
for (CustomTargetExpressionStubType stubType : getCustomStubTypes()) {
stubType.indexStub(stub, sink);
}
}
private static boolean isInstanceAttributeStub(PyTargetExpressionStub stub) {
final StubElement parent = stub.getParentStub();
return parent instanceof PyFunctionStub; // otherwise we wouldn't create the stub (see shouldCreateStub() implementation)
}
}
@@ -0,0 +1,26 @@
package com.jetbrains.python.psi.stubs;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.stubs.StubIndex;
import com.intellij.psi.stubs.StubIndexKey;
import com.jetbrains.python.psi.PyTargetExpression;
import java.util.Collection;
/**
* @author yole
*/
public class PyInstanceAttributeIndex extends StringStubIndexExtension<PyTargetExpression> {
public static final StubIndexKey<String, PyTargetExpression> KEY = StubIndexKey.createIndexKey("Py.instanceAttribute.name");
@Override
public StubIndexKey<String, PyTargetExpression> getKey() {
return KEY;
}
public static Collection<PyTargetExpression> find(String name, Project project) {
return StubIndex.getInstance().get(KEY, name, project, ProjectScope.getAllScope(project));
}
}
@@ -0,0 +1,8 @@
class MyObject:
def __init__(self):
self.xyzzy = None
def foo(p):
print p.xyzzy
# <ref>
+2 -1
View File
@@ -2,4 +2,5 @@ class A:
def long_unique_identifier(self): pass
def foo(x):
x.long_unique_identif<ref>ier()
x.long_unique_identifier()
# <ref>
@@ -6,4 +6,5 @@ class Foo:
class Bar(Foo):
pass
<ref>Bar()
Bar()
#<ref>
+2 -1
View File
@@ -1,2 +1,3 @@
import NonExistingModule
N<ref>onExistingModule.foo()
NonExistingModule.foo()
#<ref>
@@ -13,10 +13,14 @@ import com.jetbrains.python.psi.resolve.ImportedResolveResult;
public class PyResolveTest extends PyResolveTestCase {
@Override
protected PsiElement doResolve() {
final PsiReference ref = findReferenceByMarker();
return ref.resolve();
}
private PsiReference findReferenceByMarker() {
myFixture.configureByFile("resolve/" + getTestName(false) + ".py");
int offset = findMarkerOffset(myFixture.getFile());
final PsiReference ref = myFixture.getFile().findReferenceAt(offset);
return ref.resolve();
return myFixture.getFile().findReferenceAt(offset);
}
protected PsiElement resolve() {
@@ -26,7 +30,7 @@ public class PyResolveTest extends PyResolveTestCase {
}
private ResolveResult[] multiResolve() {
PsiReference ref = configureByFile("resolve/" + getTestName(false) + ".py");
PsiReference ref = findReferenceByMarker();
assertTrue(ref instanceof PsiPolyVariantReference);
return ((PsiPolyVariantReference)ref).multiResolve(false);
}
@@ -421,4 +425,11 @@ public class PyResolveTest extends PyResolveTestCase {
public void testKeywordArgument() {
assertResolvesTo(PyNamedParameter.class, "bar");
}
public void testImplicitResolveInstanceAttribute() {
ResolveResult[] resolveResults = multiResolve();
assertEquals(1, resolveResults.length);
final PsiElement psiElement = resolveResults[0].getElement();
assertTrue(psiElement instanceof PyTargetExpression && "xyzzy".equals(((PyTargetExpression)psiElement).getName()));
}
}