mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
PY-62208 Don't suggest names shorter than five characters unless it's an extended completion
Otherwise, we end up with dozens of unintentionally public names such as "s", "i", "k" even in the standard library (e.g. `this.s` or `pickletools.i`). Ideally, we should rely on .pyi stubs and the content of `__all__` to offer only explicitly exposed API, but not every module has any of those two, and it's not clear how to match .py files and the corresponding .pyi stubs fast enough for completion. GitOrigin-RevId: 163c472654e60ae63ff893142b8ddb9accc56393
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1a3e6c2a64
commit
ebba681c85
@@ -2250,8 +2250,15 @@ public abstract class PythonCommonCompletionTest extends PythonCommonTestCase {
|
||||
}
|
||||
|
||||
// PY-62208
|
||||
public void testTooCommonImportableNamesNotSuggested() {
|
||||
doMultiFileTest();
|
||||
public void testTooShortImportableNamesSuggestedOnlyInExtendedCompletion() {
|
||||
myFixture.copyDirectoryToProject(getTestName(true), "");
|
||||
myFixture.configureByFile("a.py");
|
||||
myFixture.complete(CompletionType.BASIC, 1);
|
||||
List<String> basicCompletionVariants = myFixture.getLookupElementStrings();
|
||||
assertDoesntContain(basicCompletionVariants, "c1", "c2");
|
||||
myFixture.complete(CompletionType.BASIC, 2);
|
||||
List<String> extendedCompletionVariants = myFixture.getLookupElementStrings();
|
||||
assertContainsElements(extendedCompletionVariants, "c1", "c2");
|
||||
}
|
||||
|
||||
private static void runWithImportableNamesInBasicCompletionDisabled(@NotNull Runnable action) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public final class PyClassNameCompletionContributor extends PyImportableNameComp
|
||||
// See https://plugins.jetbrains.com/plugin/18465-sputnik
|
||||
private static final boolean TRACING_WITH_SPUTNIK_ENABLED = false;
|
||||
private static final Logger LOG = Logger.getInstance(PyClassNameCompletionContributor.class);
|
||||
private static final Set<String> TOO_COMMON_NAMES = Set.of("main", "test");
|
||||
private static final int NAME_TOO_SHORT_FOR_BASIC_COMPLETION_THRESHOLD = 5;
|
||||
|
||||
public PyClassNameCompletionContributor() {
|
||||
if (TRACING_WITH_SPUTNIK_ENABLED) {
|
||||
@@ -63,7 +63,8 @@ public final class PyClassNameCompletionContributor extends PyImportableNameComp
|
||||
|
||||
@Override
|
||||
protected void doFillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
|
||||
if (!PyCodeInsightSettings.getInstance().INCLUDE_IMPORTABLE_NAMES_IN_BASIC_COMPLETION && !parameters.isExtendedCompletion()) {
|
||||
boolean isExtendedCompletion = parameters.isExtendedCompletion();
|
||||
if (!PyCodeInsightSettings.getInstance().INCLUDE_IMPORTABLE_NAMES_IN_BASIC_COMPLETION && !isExtendedCompletion) {
|
||||
return;
|
||||
}
|
||||
PsiFile originalFile = parameters.getOriginalFile();
|
||||
@@ -72,7 +73,7 @@ public final class PyClassNameCompletionContributor extends PyImportableNameComp
|
||||
PyTargetExpression targetExpr = as(position.getParent(), PyTargetExpression.class);
|
||||
boolean insideUnqualifiedReference = refExpr != null && !refExpr.isQualified();
|
||||
boolean insidePattern = targetExpr != null && position.getParent().getParent() instanceof PyCapturePattern;
|
||||
boolean insideStringLiteralInExtendedCompletion = position instanceof PyStringElement && parameters.isExtendedCompletion();
|
||||
boolean insideStringLiteralInExtendedCompletion = position instanceof PyStringElement && isExtendedCompletion;
|
||||
if (!(insideUnqualifiedReference || insidePattern || insideStringLiteralInExtendedCompletion)) {
|
||||
return;
|
||||
}
|
||||
@@ -103,7 +104,10 @@ public final class PyClassNameCompletionContributor extends PyImportableNameComp
|
||||
StubIndex.getInstance().processAllKeys(PyExportedModuleAttributeIndex.KEY, elementName -> {
|
||||
ProgressManager.checkCanceled();
|
||||
counters.scannedNames++;
|
||||
if (TOO_COMMON_NAMES.contains(elementName)) return true;
|
||||
if (elementName.length() < NAME_TOO_SHORT_FOR_BASIC_COMPLETION_THRESHOLD && !isExtendedCompletion) {
|
||||
counters.tooShortNames++;
|
||||
return true;
|
||||
}
|
||||
if (!result.getPrefixMatcher().isStartMatch(elementName)) return true;
|
||||
return stubIndex.processElements(PyExportedModuleAttributeIndex.KEY, elementName, project, scope, PyElement.class, exported -> {
|
||||
ProgressManager.checkCanceled();
|
||||
@@ -111,7 +115,7 @@ public final class PyClassNameCompletionContributor extends PyImportableNameComp
|
||||
if (name == null || namesInScope.contains(name)) return true;
|
||||
QualifiedName fqn = getFullyQualifiedName(exported);
|
||||
if (!isApplicableInInsertionContext(exported, fqn, position, typeEvalContext)) {
|
||||
counters.notApplicableInContext++;
|
||||
counters.notApplicableInContextNames++;
|
||||
return true;
|
||||
}
|
||||
if (alreadySuggested.add(fqn)) {
|
||||
@@ -141,7 +145,7 @@ public final class PyClassNameCompletionContributor extends PyImportableNameComp
|
||||
});
|
||||
}, scope);
|
||||
}, duration -> {
|
||||
LOG.debug(counters + " computed in " + duration + " ms");
|
||||
LOG.debug(counters + " computed for prefix '" + result.getPrefixMatcher().getPrefix() + "' in " + duration + " ms");
|
||||
if (TRACING_WITH_SPUTNIK_ENABLED) {
|
||||
//noinspection UseOfSystemOutOrSystemErr
|
||||
System.out.println("\1h('Importable names completion','%d')".formatted((duration / 10) * 10));
|
||||
@@ -229,16 +233,18 @@ public final class PyClassNameCompletionContributor extends PyImportableNameComp
|
||||
private static class Counters {
|
||||
int scannedNames;
|
||||
int privateNames;
|
||||
int tooShortNames;
|
||||
int notApplicableInContextNames;
|
||||
int totalVariants;
|
||||
int notApplicableInContext;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Counters{" +
|
||||
"scannedNames=" + scannedNames +
|
||||
", privateNames=" + privateNames +
|
||||
", tooShortNames=" + tooShortNames +
|
||||
", notApplicableInContextNames=" + notApplicableInContextNames +
|
||||
", totalVariants=" + totalVariants +
|
||||
", notApplicableInContext=" + notApplicableInContext +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
mai<caret>
|
||||
@@ -1 +0,0 @@
|
||||
mai<caret>
|
||||
@@ -1,2 +0,0 @@
|
||||
def main():
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
c<caret>
|
||||
@@ -0,0 +1,6 @@
|
||||
s = "foo"
|
||||
for c1, c2 in zip(s, s[1:]):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user