PY-45541 Display symbol's canonical import path as tail text in the lookup

Previously, we used the corresponding element's presentation for this purpose,
but it showed the shortest qualified name of its module, not necessarily the
"canonical" name that was actually used for importing. For instance, we could
have suggested `ndarray` from `numpy.core._multiarray_umath` but imported it
as `from numpy import ndarray`. It was both misleading and could have led to
duplicate entries for the same symbol among suggestions.

GitOrigin-RevId: abb350feeac9fd212d47dc0943442e0b16b21c9a
This commit is contained in:
Mikhail Golubev
2020-12-04 15:49:31 +00:00
committed by intellij-monorepo-bot
parent cd003c487b
commit 591ccf3126
5 changed files with 30 additions and 9 deletions
@@ -7,8 +7,6 @@ import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.PrioritizedLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
@@ -24,6 +22,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.search.PySearchUtilBase;
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
import com.jetbrains.python.psi.stubs.PyFunctionNameIndex;
@@ -125,16 +124,15 @@ public class PyClassNameCompletionContributor extends PyExtendedCompletionContri
ProgressManager.checkCanceled();
if (!condition.value(element)) return true;
String name = element.getName();
ItemPresentation itemPresentation = ((NavigationItem)element).getPresentation();
if (name == null || itemPresentation == null) return true;
String locationString = itemPresentation.getLocationString();
if (locationString == null) return true;
String uniquenessKey = name + locationString;
if (alreadySuggested.add(uniquenessKey)) {
if (name == null) return true;
QualifiedName importPath = QualifiedNameFinder.findCanonicalImportPath(element, targetFile);
if (importPath == null) return true;
String qualifiedName = importPath + "." + name;
if (alreadySuggested.add(qualifiedName)) {
LookupElementBuilder lookupElement = LookupElementBuilder
.createWithSmartPointer(name, element)
.withIcon(element.getIcon(0))
.withTailText(" " + locationString, true)
.withTailText(" (" + importPath + ")", true)
.withInsertHandler(insertHandler);
resultSet.addElement(elementHandler.apply(lookupElement));
}
@@ -0,0 +1 @@
from .mod import my_func
@@ -0,0 +1,5 @@
def my_func():
pass
my_var = 42
@@ -8,6 +8,8 @@ import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.testFramework.fixtures.TestLookupElementPresentation;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.formatter.PyCodeStyleSettings;
@@ -164,6 +166,20 @@ public class PyClassNameCompletionTest extends PyTestCase {
assertEquals(1, Collections.frequency(allVariants, "my_func"));
}
// PY-45541
public void testCanonicalImportPathUsedAsLookupTailText() {
LookupElement[] lookupElements = doExtendedCompletion();
LookupElement reexportedFunc = ContainerUtil.find(lookupElements, variant -> variant.getLookupString().equals("my_func"));
assertNotNull(reexportedFunc);
TestLookupElementPresentation funcPresentation = TestLookupElementPresentation.renderReal(reexportedFunc);
assertEquals(" (pkg)", funcPresentation.getTailText());
LookupElement notExportedVar = ContainerUtil.find(lookupElements, variant -> variant.getLookupString().equals("my_var"));
assertNotNull(notExportedVar);
TestLookupElementPresentation varPresentation = TestLookupElementPresentation.renderReal(notExportedVar);
assertEquals(" (pkg.mod)", varPresentation.getTailText());
}
private void doTest() {
LookupElement[] lookupElements = doExtendedCompletion();
if (lookupElements != null) {