PY-26881 Use stubs for function in find usages if it exists

(cherry picked from commit 060c164c3f01a857561d5d0341a186464419e845)

IJ-MR-17639

GitOrigin-RevId: 88141ea74ff22fb022056c8d6d7f70222a3f9b74
This commit is contained in:
andrey.matveev
2021-10-01 13:30:24 +07:00
committed by intellij-monorepo-bot
parent 056ac17679
commit 0210695327
19 changed files with 143 additions and 30 deletions

View File

@@ -1127,3 +1127,9 @@ INSP.relative.import.relative.import.outside.package=Relative import outside of
debugger.cleaning.signature.cache=Cleaning the Cache of Dynamically Collected Types
ANN.patterns.repeated.star.pattern=Repeated star pattern
# PyElementPresentation
element.presentation.location.string.in.class={0} in {1}
element.presentation.location.string.in.class.stub={0} in {1} stub
element.presentation.location.string.module={0}
element.presentation.location.string.module.stub={0} stub

View File

@@ -19,9 +19,14 @@ import com.intellij.find.findUsages.FindUsagesHandlerBase;
import com.intellij.find.findUsages.FindUsagesOptions;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.pyi.PyiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Important note: please update PyFindUsagesHandlerFactory#proxy on any changes here.
*/
@@ -41,4 +46,44 @@ public abstract class PyFindUsagesHandler extends FindUsagesHandlerBase {
public boolean isSearchForTextOccurrencesAvailable(@NotNull PsiElement psiElement, boolean isSingleFile) {
return super.isSearchForTextOccurrencesAvailable(psiElement, isSingleFile);
}
@Override
public PsiElement @NotNull [] getPrimaryElements() {
List<PsiElement> result = new ArrayList<>();
result.add(myPsiElement);
completePrimaryElementsWithStubAndOriginalElements(result);
return result.toArray(PsiElement.EMPTY_ARRAY);
}
protected void completePrimaryElementsWithStubAndOriginalElements(@NotNull List<PsiElement> result) {
List<PsiElement> additionalElements = new ArrayList<>();
for (PsiElement element: result) {
PsiElement stubElement = tryGetStubElement(element);
if (stubElement != null) {
additionalElements.add(stubElement);
}
PsiElement originalElement = tryGetOriginalElement(element);
if (originalElement != null) {
additionalElements.add(originalElement);
}
}
result.addAll(additionalElements);
}
@Nullable
protected static PsiElement tryGetStubElement(@Nullable PsiElement element) {
if (!(element instanceof PyElement)) return null;
PsiElement result = PyiUtil.getPythonStub((PyElement)element);
return result != element ? result : null;
}
@Nullable
protected static PsiElement tryGetOriginalElement(@Nullable PsiElement element) {
if (!(element instanceof PyElement)) return null;
PsiElement result = PyiUtil.getOriginalElement((PyElement)element);
return result != element ? result : null;
}
}

View File

@@ -18,6 +18,7 @@ package com.jetbrains.python.findUsages;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
@@ -43,6 +44,16 @@ public class PyFunctionFindUsagesHandler extends PyFindUsagesHandler {
@Override
public PsiElement @NotNull [] getPrimaryElements() {
return myAllElements != null ? myAllElements.toArray(PsiElement.EMPTY_ARRAY) : super.getPrimaryElements();
List<PsiElement> result = new ArrayList<>();
if (myAllElements != null) {
result.addAll(myAllElements);
}
else {
result.add(myPsiElement);
}
completePrimaryElementsWithStubAndOriginalElements(result);
return result.toArray(PsiElement.EMPTY_ARRAY);
}
}

View File

@@ -20,12 +20,16 @@ import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyPsiBundle;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyPossibleClassMember;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.pyi.PyiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.Icon;
import javax.swing.*;
/**
* @author vlan
@@ -53,8 +57,29 @@ public class PyElementPresentation implements ColoredItemPresentation {
@Nullable
@Override
public String getLocationString() {
String packageForFile = getPackageForFile(myElement.getContainingFile());
return packageForFile != null ? String.format("(%s)", packageForFile) : null;
PsiFile containingFile = myElement.getContainingFile();
String packageForFile = getPackageForFile(containingFile);
if (packageForFile == null) return null;
boolean isPyiFile = containingFile instanceof PyiFile;
PyClass containingClass = myElement instanceof PyPossibleClassMember ? ((PyPossibleClassMember)myElement).getContainingClass() : null;
if (containingClass != null) {
if (isPyiFile) {
return PyPsiBundle.message("element.presentation.location.string.in.class.stub", containingClass.getName(), packageForFile);
}
else {
return PyPsiBundle.message("element.presentation.location.string.in.class", containingClass.getName(), packageForFile);
}
}
if (isPyiFile) {
return PyPsiBundle.message("element.presentation.location.string.module", packageForFile);
}
else {
return PyPsiBundle.message("element.presentation.location.string.module.stub", packageForFile);
}
}
@Nullable

View File

@@ -33,7 +33,6 @@ import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.pyi.PyiFile;
import com.jetbrains.python.sdk.PythonSdkUtil;
import icons.PythonPsiApiIcons;
import org.jetbrains.annotations.NotNull;
@@ -298,19 +297,6 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
public String getPresentableText() {
return notNullize(getName(), PyNames.UNNAMED_ELEMENT) + getParameterList().getPresentableText(true);
}
@Nullable
@Override
public String getLocationString() {
final PyClass containingClass = getContainingClass();
final PsiFile containingFile = getContainingFile();
final String packageForFile = getPackageForFile(containingFile);
if (containingClass != null && packageForFile != null) {
final String fileInfoStr = containingFile instanceof PyiFile ? packageForFile + " stub" : packageForFile;
return String.format("(%s in %s)", containingClass.getName(), fileInfoStr);
}
return super.getLocationString();
}
};
}

View File

@@ -653,18 +653,7 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl<PyTargetExpression
@Override
public ItemPresentation getPresentation() {
return new PyElementPresentation(this) {
@Nullable
@Override
public String getLocationString() {
final PyClass containingClass = getContainingClass();
final String packageForFile = getPackageForFile(getContainingFile());
if (containingClass != null && packageForFile != null) {
return String.format("(%s in %s)", containingClass.getName(), packageForFile);
}
return super.getLocationString();
}
};
return new PyElementPresentation(this);
}
@Nullable

View File

@@ -0,0 +1,3 @@
from parent import Parent
class Child(Parent):
FO<caret>O = 'bar'

View File

@@ -0,0 +1,2 @@
class Parent(object):
FOO = 'foo'

View File

@@ -0,0 +1,2 @@
class Parent(object):
FOO: str

View File

@@ -0,0 +1,3 @@
from parent import Parent
class Child(Parent):
FOO = 'bar'

View File

@@ -0,0 +1,2 @@
class Parent(object):
FO<caret>O = 'foo'

View File

@@ -0,0 +1,2 @@
class Parent(object):
FOO: str

View File

@@ -0,0 +1,3 @@
from parent import Parent
class Child(Parent):
pass

View File

@@ -0,0 +1,2 @@
class Pare<caret>nt(object):
pass

View File

@@ -0,0 +1,2 @@
class Parent(object):
pass

View File

@@ -0,0 +1,3 @@
from lib import foo
foo()

View File

@@ -0,0 +1,2 @@
def fo<caret>o():
print("42")

View File

@@ -0,0 +1 @@
def foo(): ...

View File

@@ -199,6 +199,30 @@ public class PyFindUsagesTest extends PyTestCase {
.size());
}
// PY-26881
public void testFunctionHasPyiStub() {
final Collection<UsageInfo> usages = findMultiFileUsages("lib.py");
assertEquals(2, usages.size());
}
// PY-26881
public void testClassHasPyiStub() {
final Collection<UsageInfo> usages = findMultiFileUsages("parent.py");
assertEquals(2, usages.size());
}
// PY-26881
public void testClassAttributeHasPyiStub() {
final Collection<UsageInfo> usages = findMultiFileUsages("parent.py");
assertEquals(3, usages.size());
}
// PY-26881
public void testChildClassAttributeHasPyiStub() {
final Collection<UsageInfo> usages = findMultiFileUsages("child.py");
assertEquals(2, usages.size());
}
private Collection<UsageInfo> findMultiFileUsages(String filename) {
final String testName = getTestName(false);
myFixture.copyDirectoryToProject("findUsages/" + testName, "");