mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
implicit resolve works also for instance attributes (PY-4292)
This commit is contained in:
@@ -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,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>
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user