From 6749423692ef91d0eb090d894f2ad256a0fdf4f9 Mon Sep 17 00:00:00 2001 From: UNV Date: Mon, 12 Oct 2026 18:34:19 +0300 Subject: [PATCH] Fixing compilation errors after platform localization. Some refactoring. --- .../PyElementDescriptionProvider.java | 10 +- .../python/impl/psi/impl/PyClassImpl.java | 23 +- .../impl/psi/impl/PyElementPresentation.java | 79 ++- .../python/impl/psi/impl/PyFileImpl.java | 5 +- .../python/impl/psi/impl/PyFunctionImpl.java | 9 +- .../impl/psi/impl/PyImportElementImpl.java | 469 ++++++++---------- .../impl/psi/impl/PyParameterListImpl.java | 325 ++++++------ .../psi/impl/PyStarImportElementImpl.java | 219 ++++---- .../impl/PyStringLiteralExpressionImpl.java | 12 +- .../structureView/PyStructureViewElement.java | 429 ++++++++-------- .../java/com/jetbrains/python/PyNames.java | 3 +- .../jetbrains/python/psi/PyParameterList.java | 70 ++- 12 files changed, 783 insertions(+), 870 deletions(-) diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/findUsages/PyElementDescriptionProvider.java b/python-impl/src/main/java/com/jetbrains/python/impl/findUsages/PyElementDescriptionProvider.java index 82d14b90..9df2fc4b 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/findUsages/PyElementDescriptionProvider.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/findUsages/PyElementDescriptionProvider.java @@ -22,6 +22,7 @@ import consulo.language.psi.ElementDescriptionProvider; import consulo.language.psi.PsiElement; import consulo.language.psi.PsiNamedElement; +import consulo.localize.LocalizeValue; import consulo.usage.UsageViewLongNameLocation; /** @@ -31,8 +32,11 @@ public class PyElementDescriptionProvider implements ElementDescriptionProvider { @Override @RequiredReadAction - public String getElementDescription(PsiElement element, ElementDescriptionLocation location) { - return location instanceof UsageViewLongNameLocation && element instanceof PsiNamedElement namedElem && namedElem instanceof PyElement - ? namedElem.getName() : null; + public LocalizeValue getElementDescription(PsiElement element, ElementDescriptionLocation location) { + return location instanceof UsageViewLongNameLocation + && element instanceof PsiNamedElement namedElem + && namedElem instanceof PyElement + ? LocalizeValue.ofNullable(namedElem.getName()) + : LocalizeValue.empty(); } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyClassImpl.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyClassImpl.java index 670ca40a..c5910c7f 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyClassImpl.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyClassImpl.java @@ -57,11 +57,13 @@ import consulo.language.psi.util.PsiTreeUtil; import consulo.language.psi.util.QualifiedName; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.navigation.ItemPresentation; import consulo.util.collection.ArrayFactory; import consulo.util.collection.ContainerUtil; import consulo.util.collection.SmartList; import consulo.util.lang.Comparing; +import consulo.util.lang.StringUtil; import consulo.util.lang.ref.SimpleReference; import org.jspecify.annotations.Nullable; @@ -69,7 +71,6 @@ import java.util.function.Function; import java.util.function.Predicate; -import static consulo.util.lang.StringUtil.join; import static consulo.util.lang.StringUtil.notNullize; /** @@ -370,22 +371,26 @@ public PyClass[] getSuperClasses(@Nullable TypeEvalContext context) { @Override public ItemPresentation getPresentation() { return new PyElementPresentation(this) { - @Nullable @Override @RequiredReadAction - public String getPresentableText() { + public LocalizeValue getPresentableText() { PyPsiUtils.assertValid(PyClassImpl.this); - StringBuilder result = new StringBuilder(notNullize(getName(), PyNames.UNNAMED_ELEMENT)); + StringBuilder result = new StringBuilder(notNullize(getName(), PyNames.UNNAMED_ELEMENT.get())); PyExpression[] superClassExpressions = getSuperClassExpressions(); if (superClassExpressions.length > 0) { result.append("("); - result.append(join(Arrays.asList(superClassExpressions), expr -> { - String name = expr.getText(); - return notNullize(name, PyNames.UNNAMED_ELEMENT); - }, ", ")); + StringUtil.join( + superClassExpressions, + expr -> { + String name = expr.getText(); + return notNullize(name, PyNames.UNNAMED_ELEMENT.get()); + }, + ", ", + result + ); result.append(")"); } - return result.toString(); + return LocalizeValue.of(result.toString()); } }; } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyElementPresentation.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyElementPresentation.java index 73f6d5c9..899ab490 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyElementPresentation.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyElementPresentation.java @@ -15,6 +15,8 @@ */ package com.jetbrains.python.impl.psi.impl; +import consulo.annotation.access.RequiredReadAction; +import consulo.localize.LocalizeValue; import org.jspecify.annotations.Nullable; import consulo.ui.ex.ColoredItemPresentation; @@ -30,56 +32,43 @@ /** * @author vlan */ -public class PyElementPresentation implements ColoredItemPresentation -{ - private final PyElement myElement; +public class PyElementPresentation implements ColoredItemPresentation { + private final PyElement myElement; - public PyElementPresentation(PyElement element) - { - myElement = element; - } + public PyElementPresentation(PyElement element) { + myElement = element; + } - @Nullable - @Override - public TextAttributesKey getTextAttributesKey() - { - return null; - } + @Override + public @Nullable TextAttributesKey getTextAttributesKey() { + return null; + } - @Nullable - @Override - public String getPresentableText() - { - String name = myElement.getName(); - return name != null ? name : PyNames.UNNAMED_ELEMENT; - } + @Override + public LocalizeValue getPresentableText() { + return LocalizeValue.ofNullable(myElement.getName()).orIfEmpty(PyNames.UNNAMED_ELEMENT); + } - @Nullable - @Override - public String getLocationString() - { - return "(" + getPackageForFile(myElement.getContainingFile()) + ")"; - } + @Override + public @Nullable String getLocationString() { + return "(" + getPackageForFile(myElement.getContainingFile()) + ")"; + } - @Nullable - @Override - public Image getIcon() - { - return IconDescriptorUpdaters.getIcon(myElement, 0); - } + @Override + @RequiredReadAction + public @Nullable Image getIcon() { + return IconDescriptorUpdaters.getIcon(myElement, 0); + } - public static String getPackageForFile(PsiFile containingFile) - { - VirtualFile vFile = containingFile.getVirtualFile(); + public static String getPackageForFile(PsiFile containingFile) { + VirtualFile vFile = containingFile.getVirtualFile(); - if(vFile != null) - { - String importableName = QualifiedNameFinder.findShortestImportableName(containingFile, vFile); - if(importableName != null) - { - return importableName; - } - } - return ""; - } + if (vFile != null) { + String importableName = QualifiedNameFinder.findShortestImportableName(containingFile, vFile); + if (importableName != null) { + return importableName; + } + } + return ""; + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFileImpl.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFileImpl.java index 337e0b68..056a7323 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFileImpl.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFileImpl.java @@ -50,6 +50,7 @@ import consulo.language.psi.util.PsiTreeUtil; import consulo.language.psi.util.QualifiedName; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.module.content.ProjectFileIndex; import consulo.navigation.ItemPresentation; import consulo.platform.base.icon.PlatformIconGroup; @@ -773,8 +774,8 @@ public ItemPresentation getPresentation() { return new ItemPresentation() { @Override @RequiredReadAction - public String getPresentableText() { - return getModuleName(PyFileImpl.this); + public LocalizeValue getPresentableText() { + return LocalizeValue.of(getModuleName(PyFileImpl.this)); } @Override diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFunctionImpl.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFunctionImpl.java index 11db9379..2b80bdb6 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFunctionImpl.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyFunctionImpl.java @@ -54,6 +54,7 @@ import consulo.language.psi.util.LanguageCachedValueUtil; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.navigation.ItemPresentation; import consulo.platform.base.icon.PlatformIconGroup; import consulo.python.impl.icon.PythonImplIconGroup; @@ -288,11 +289,13 @@ private PyType analyzeCallType( @Override public ItemPresentation getPresentation() { return new PyElementPresentation(this) { - @Nullable @Override @RequiredReadAction - public String getPresentableText() { - return notNullize(getName(), PyNames.UNNAMED_ELEMENT) + getParameterList().getPresentableText(true); + public LocalizeValue getPresentableText() { + return LocalizeValue.join( + LocalizeValue.ofNullable(getName()).orIfEmpty(PyNames.UNNAMED_ELEMENT), + getParameterList().getPresentableText(true) + ); } @Nullable diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyImportElementImpl.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyImportElementImpl.java index 5e5b262e..8b6afc20 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyImportElementImpl.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyImportElementImpl.java @@ -25,16 +25,17 @@ import consulo.annotation.access.RequiredReadAction; import consulo.language.ast.ASTNode; import consulo.language.psi.PsiElement; -import consulo.language.psi.PsiFile; import consulo.language.psi.stub.IStubElementType; import consulo.language.psi.util.PsiTreeUtil; import consulo.language.psi.util.QualifiedName; +import consulo.localize.LocalizeValue; import consulo.navigation.ItemPresentation; import consulo.ui.image.Image; import consulo.util.lang.Comparing; import consulo.util.lang.StringUtil; import org.jspecify.annotations.Nullable; + import java.util.Collections; import java.util.List; @@ -43,305 +44,249 @@ * * @author yole */ -public class PyImportElementImpl extends PyBaseElementImpl implements PyImportElement -{ - public PyImportElementImpl(ASTNode astNode) - { - super(astNode); - } +public class PyImportElementImpl extends PyBaseElementImpl implements PyImportElement { + public PyImportElementImpl(ASTNode astNode) { + super(astNode); + } - public PyImportElementImpl(PyImportElementStub stub) - { - this(stub, PyElementTypes.IMPORT_ELEMENT); - } + public PyImportElementImpl(PyImportElementStub stub) { + this(stub, PyElementTypes.IMPORT_ELEMENT); + } - public PyImportElementImpl(PyImportElementStub stub, IStubElementType nodeType) - { - super(stub, nodeType); - } + public PyImportElementImpl(PyImportElementStub stub, IStubElementType nodeType) { + super(stub, nodeType); + } @Nullable @Override @RequiredReadAction - public PyReferenceExpression getImportReferenceExpression() - { - ASTNode node = getNode().findChildByType(PythonDialectsTokenSetProvider.INSTANCE.getReferenceExpressionTokens()); - return node == null ? null : (PyReferenceExpression) node.getPsi(); - } + public PyReferenceExpression getImportReferenceExpression() { + ASTNode node = getNode().findChildByType(PythonDialectsTokenSetProvider.INSTANCE.getReferenceExpressionTokens()); + return node == null ? null : (PyReferenceExpression) node.getPsi(); + } - @Override + @Override @RequiredReadAction - public QualifiedName getImportedQName() - { - PyImportElementStub stub = getStub(); - if(stub != null) - { - return stub.getImportedQName(); - } - PyReferenceExpression importReference = getImportReferenceExpression(); - return importReference != null ? importReference.asQualifiedName() : null; - } + public QualifiedName getImportedQName() { + PyImportElementStub stub = getStub(); + if (stub != null) { + return stub.getImportedQName(); + } + PyReferenceExpression importReference = getImportReferenceExpression(); + return importReference != null ? importReference.asQualifiedName() : null; + } @Override @RequiredReadAction - public PyTargetExpression getAsNameElement() - { - return getStubOrPsiChild(PyElementTypes.TARGET_EXPRESSION); - } + public PyTargetExpression getAsNameElement() { + return getStubOrPsiChild(PyElementTypes.TARGET_EXPRESSION); + } - @Override + @Override @RequiredReadAction - public String getAsName() - { - PyImportElementStub stub = getStub(); - if(stub != null) - { - String asName = stub.getAsName(); - return StringUtil.isEmpty(asName) ? null : asName; - } - PyTargetExpression element = getAsNameElement(); - return element != null ? element.getName() : null; - } + public String getAsName() { + PyImportElementStub stub = getStub(); + if (stub != null) { + String asName = stub.getAsName(); + return StringUtil.isEmpty(asName) ? null : asName; + } + PyTargetExpression element = getAsNameElement(); + return element != null ? element.getName() : null; + } - @Override - @Nullable + @Override + @Nullable @RequiredReadAction - public String getVisibleName() - { - PyImportElementStub stub = getStub(); - if(stub != null) - { - String asName = stub.getAsName(); - if(!StringUtil.isEmpty(asName)) - { - return asName; - } - QualifiedName importedName = stub.getImportedQName(); - if(importedName != null && importedName.getComponentCount() > 0) - { - return importedName.getComponents().get(0); - } - } - else - { - PyTargetExpression asNameElement = getAsNameElement(); - if(asNameElement != null) - { - return asNameElement.getName(); - } - QualifiedName importedName = getImportedQName(); - if(importedName != null && importedName.getComponentCount() > 0) - { - return importedName.getComponents().get(0); - } - } - return null; // we might have not found any names - } + public String getVisibleName() { + PyImportElementStub stub = getStub(); + if (stub != null) { + String asName = stub.getAsName(); + if (!StringUtil.isEmpty(asName)) { + return asName; + } + QualifiedName importedName = stub.getImportedQName(); + if (importedName != null && importedName.getComponentCount() > 0) { + return importedName.getComponents().get(0); + } + } + else { + PyTargetExpression asNameElement = getAsNameElement(); + if (asNameElement != null) { + return asNameElement.getName(); + } + QualifiedName importedName = getImportedQName(); + if (importedName != null && importedName.getComponentCount() > 0) { + return importedName.getComponents().get(0); + } + } + return null; // we might have not found any names + } - @Nullable + @Nullable @Override @RequiredReadAction - public PyStatement getContainingImportStatement() - { - PyImportElementStub stub = getStub(); - PsiElement parent; - if(stub != null) - { - parent = stub.getParentStub().getPsi(); - } - else - { - parent = getParent(); - } - return parent instanceof PyStatement ? (PyStatement) parent : null; - } + public PyStatement getContainingImportStatement() { + PyImportElementStub stub = getStub(); + PsiElement parent; + if (stub != null) { + parent = stub.getParentStub().getPsi(); + } + else { + parent = getParent(); + } + return parent instanceof PyStatement ? (PyStatement) parent : null; + } - @Override - public ItemPresentation getPresentation() - { - return new ItemPresentation() - { - @RequiredReadAction - private String getRefName(String default_name) - { - PyReferenceExpression ref = getImportReferenceExpression(); - if(ref != null) - { - String refName = ref.getName(); - if(refName != null) - { - return refName; - } - } - return default_name; - } + @Override + public ItemPresentation getPresentation() { + return new ItemPresentation() { + @RequiredReadAction + private String getRefName(String defaultName) { + PyReferenceExpression ref = getImportReferenceExpression(); + if (ref != null) { + String refName = ref.getName(); + if (refName != null) { + return refName; + } + } + return defaultName; + } - @Override + @Override @RequiredReadAction - public String getPresentableText() - { - return getRefName(""); - } + public LocalizeValue getPresentableText() { + return LocalizeValue.localizeTODO(getRefName("")); + } - @Override + @Override @RequiredReadAction - public String getLocationString() - { - PyElement elt = PsiTreeUtil.getParentOfType(PyImportElementImpl.this, PyImportStatement.class, PyFromImportStatement.class); - StringBuilder buf = new StringBuilder("| "); - if(elt != null) - { // always? who knows :) - if(elt instanceof PyFromImportStatement) - { // from ... import ... - buf.append("from "); - PyReferenceExpression imp_src = ((PyFromImportStatement) elt).getImportSource(); - if(imp_src != null) - { - buf.append(PyPsiUtils.toPath(imp_src)); - } - else - { - buf.append(""); - } - buf.append(" import "); - } - else - { // "import ... " - buf.append("import "); - } - buf.append(getRefName("")); - } - else - { - buf.append("import?.. "); - } - // are we the name or the 'as'? - PyTargetExpression as_part = getAsNameElement(); - if(as_part != null) - { - buf.append(" as ").append(as_part.getName()); - } - return buf.toString(); - } + public String getLocationString() { + PyElement elt = PsiTreeUtil.getParentOfType(PyImportElementImpl.this, PyImportStatement.class, PyFromImportStatement.class); + StringBuilder buf = new StringBuilder("| "); + if (elt != null) { // always? who knows :) + if (elt instanceof PyFromImportStatement) { // from ... import ... + buf.append("from "); + PyReferenceExpression imp_src = ((PyFromImportStatement) elt).getImportSource(); + if (imp_src != null) { + buf.append(PyPsiUtils.toPath(imp_src)); + } + else { + buf.append(""); + } + buf.append(" import "); + } + else { // "import ... " + buf.append("import "); + } + buf.append(getRefName("")); + } + else { + buf.append("import?.. "); + } + // are we the name or the 'as'? + PyTargetExpression as_part = getAsNameElement(); + if (as_part != null) { + buf.append(" as ").append(as_part.getName()); + } + return buf.toString(); + } - @Override - public Image getIcon() - { - return null; - } - }; - } + @Override + public Image getIcon() { + return null; + } + }; + } @Override @RequiredReadAction - public Iterable iterateNames() - { - PyElement ret = getAsNameElement(); - if(ret == null) - { - PyReferenceExpression importReference = getImportReferenceExpression(); - if(importReference != null) - { - ret = PyPsiUtils.getFirstQualifier(importReference); - } - } - if(ret == null) - { - return List.of(); - } - return Collections.singleton(ret); - } + public Iterable iterateNames() { + PyElement ret = getAsNameElement(); + if (ret == null) { + PyReferenceExpression importReference = getImportReferenceExpression(); + if (importReference != null) { + ret = PyPsiUtils.getFirstQualifier(importReference); + } + } + if (ret == null) { + return List.of(); + } + return Collections.singleton(ret); + } - @Override + @Override @RequiredReadAction - public List multiResolveName(String name) - { - return getElementsNamed(name, true); - } + public List multiResolveName(String name) { + return getElementsNamed(name, true); + } - @Nullable - @Override + @Nullable + @Override @RequiredReadAction - public PsiElement getElementNamed(String name, boolean resolveImportElement) - { - List results = getElementsNamed(name, resolveImportElement); - return results.isEmpty() ? null : RatedResolveResult.sorted(results).get(0).getElement(); - } + public PsiElement getElementNamed(String name, boolean resolveImportElement) { + List results = getElementsNamed(name, resolveImportElement); + return results.isEmpty() ? null : RatedResolveResult.sorted(results).get(0).getElement(); + } - @RequiredReadAction - private List getElementsNamed(String name, boolean resolveImportElement) - { - String asName = getAsName(); - if(asName != null) - { - if(!Comparing.equal(name, asName)) - { - return Collections.emptyList(); - } - if(resolveImportElement) - { - return multiResolve(); - } - return ResolveResultList.to(this); - } - else - { - QualifiedName qName = getImportedQName(); - if(qName == null || qName.getComponentCount() == 0 || !qName.getComponents().get(0).equals(name)) - { - return Collections.emptyList(); - } - if(qName.getComponentCount() == 1) - { - if(resolveImportElement) - { - return multiResolve(); - } - return ResolveResultList.to(this); - } - return ResolveResultList.to(createImportedModule(name)); - } - } + @RequiredReadAction + private List getElementsNamed(String name, boolean resolveImportElement) { + String asName = getAsName(); + if (asName != null) { + if (!Comparing.equal(name, asName)) { + return Collections.emptyList(); + } + if (resolveImportElement) { + return multiResolve(); + } + return ResolveResultList.to(this); + } + else { + QualifiedName qName = getImportedQName(); + if (qName == null || qName.getComponentCount() == 0 || !qName.getComponents().get(0).equals(name)) { + return Collections.emptyList(); + } + if (qName.getComponentCount() == 1) { + if (resolveImportElement) { + return multiResolve(); + } + return ResolveResultList.to(this); + } + return ResolveResultList.to(createImportedModule(name)); + } + } - @Nullable - @Override + @Nullable + @Override @RequiredReadAction - public PsiElement resolve() - { - List results = multiResolve(); - return results.isEmpty() ? null : RatedResolveResult.sorted(results).get(0).getElement(); - } + public PsiElement resolve() { + List results = multiResolve(); + return results.isEmpty() ? null : RatedResolveResult.sorted(results).get(0).getElement(); + } - @Override + @Override @RequiredReadAction - public List multiResolve() - { - QualifiedName qName = getImportedQName(); - return qName == null ? Collections.emptyList() : ResolveImportUtil.multiResolveImportElement(this, qName); - } + public List multiResolve() { + QualifiedName qName = getImportedQName(); + return qName == null ? Collections.emptyList() : ResolveImportUtil.multiResolveImportElement(this, qName); + } - @Override - protected void acceptPyVisitor(PyElementVisitor pyVisitor) - { - pyVisitor.visitPyImportElement(this); - } + @Override + protected void acceptPyVisitor(PyElementVisitor pyVisitor) { + pyVisitor.visitPyImportElement(this); + } - @Override + @Override @RequiredReadAction - public String toString() - { - QualifiedName qName = getImportedQName(); - return String.format("%s:%s", super.toString(), qName != null ? qName : "null"); - } + public String toString() { + QualifiedName qName = getImportedQName(); + return String.format("%s:%s", super.toString(), qName != null ? qName : "null"); + } - @Nullable - private PsiElement createImportedModule(String name) - { - PsiFile file = getContainingFile(); - if(file instanceof PyFile) - { - return new PyImportedModule(this, (PyFile) file, QualifiedName.fromComponents(name)); - } - return null; - } + @Nullable + private PsiElement createImportedModule(String name) { + if (getContainingFile() instanceof PyFile pyFile) { + return new PyImportedModule(this, pyFile, QualifiedName.fromComponents(name)); + } + return null; + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyParameterListImpl.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyParameterListImpl.java index faa9c3fa..61c59ee3 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyParameterListImpl.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyParameterListImpl.java @@ -22,180 +22,171 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.stubs.PyParameterListStub; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; import consulo.language.ast.ASTNode; import consulo.language.psi.PsiElement; import consulo.language.psi.stub.IStubElementType; +import consulo.localize.LocalizeValue; import consulo.util.collection.ArrayUtil; -import consulo.util.lang.ref.Ref; - +import consulo.util.lang.ref.SimpleReference; import org.jspecify.annotations.Nullable; /** * @author yole */ -public class PyParameterListImpl extends PyBaseElementImpl implements PyParameterList -{ - public PyParameterListImpl(ASTNode astNode) - { - super(astNode); - } - - public PyParameterListImpl(PyParameterListStub stub) - { - this(stub, PyElementTypes.PARAMETER_LIST); - } - - public PyParameterListImpl(PyParameterListStub stub, IStubElementType nodeType) - { - super(stub, nodeType); - } - - @Override - protected void acceptPyVisitor(PyElementVisitor pyVisitor) - { - pyVisitor.visitPyParameterList(this); - } - - public PyParameter[] getParameters() - { - return getStubOrPsiChildren(PythonDialectsTokenSetProvider.INSTANCE.getParameterTokens(), new PyParameter[0]); - } - - public void addParameter(PyNamedParameter param) - { - PsiElement paren = getLastChild(); - if(paren != null && ")".equals(paren.getText())) - { - ASTNode beforeWhat = paren.getNode(); // the closing paren will be this - PyParameter[] params = getParameters(); - boolean hasDefaultValue = param.hasDefaultValue(); - boolean isLast = true; - for(PyParameter p : params) - { - if(!hasDefaultValue && p.hasDefaultValue()) - { - beforeWhat = p.getNode(); - isLast = false; - break; - } - if(p instanceof PyNamedParameter) - { - PyNamedParameter named = (PyNamedParameter) p; - if(named.isKeywordContainer() || named.isPositionalContainer()) - { - beforeWhat = p.getNode(); - isLast = false; - break; - } - } - } - ASTNode previous = PyPsiUtils.getPrevNonWhitespaceSibling(beforeWhat); - PyUtil.addListNode(this, param, beforeWhat, !isLast || params.length == 0 || - previous.getElementType() == PyTokenTypes.COMMA, isLast, beforeWhat.getElementType() != PyTokenTypes.RPAR); - } - } - - public boolean hasPositionalContainer() - { - for(PyParameter parameter : getParameters()) - { - if(parameter instanceof PyNamedParameter && ((PyNamedParameter) parameter).isPositionalContainer()) - { - return true; - } - } - return false; - } - - public boolean hasKeywordContainer() - { - for(PyParameter parameter : getParameters()) - { - if(parameter instanceof PyNamedParameter && ((PyNamedParameter) parameter).isKeywordContainer()) - { - return true; - } - } - return false; - } - - @Override - @Nullable - public PyNamedParameter findParameterByName(final String name) - { - final Ref result = new Ref<>(); - ParamHelper.walkDownParamArray(getParameters(), new ParamHelper.ParamVisitor() - { - @Override - public void visitNamedParameter(PyNamedParameter param, boolean first, boolean last) - { - if(name.equals(param.getName())) - { - result.set(param); - } - } - }); - return result.get(); - } - - public String getPresentableText(final boolean includeDefaultValue) - { - final StringBuilder target = new StringBuilder(); - final String COMMA = ", "; - target.append("("); - ParamHelper.walkDownParamArray(getParameters(), new ParamHelper.ParamWalker() - { - public void enterTupleParameter(PyTupleParameter param, boolean first, boolean last) - { - target.append("("); - } - - public void leaveTupleParameter(PyTupleParameter param, boolean first, boolean last) - { - target.append(")"); - if(!last) - { - target.append(COMMA); - } - } - - public void visitNamedParameter(PyNamedParameter param, boolean first, boolean last) - { - target.append(param.getRepr(includeDefaultValue)); - if(!last) - { - target.append(COMMA); - } - } - - public void visitSingleStarParameter(PySingleStarParameter param, boolean first, boolean last) - { - target.append('*'); - if(!last) - { - target.append(COMMA); - } - } - }); - target.append(")"); - return target.toString(); - } - - @Nullable - @Override - public PyFunction getContainingFunction() - { - PsiElement parent = getParentByStub(); - return parent instanceof PyFunction ? (PyFunction) parent : null; - } - - @Override - public void deleteChildInternal(ASTNode node) - { - if(ArrayUtil.contains(node.getPsi(), getParameters())) - { - PyPsiUtils.deleteAdjacentCommaWithWhitespaces(this, node.getPsi()); - } - super.deleteChildInternal(node); - } +public class PyParameterListImpl extends PyBaseElementImpl implements PyParameterList { + public PyParameterListImpl(ASTNode astNode) { + super(astNode); + } + + public PyParameterListImpl(PyParameterListStub stub) { + this(stub, PyElementTypes.PARAMETER_LIST); + } + + public PyParameterListImpl(PyParameterListStub stub, IStubElementType nodeType) { + super(stub, nodeType); + } + + @Override + protected void acceptPyVisitor(PyElementVisitor pyVisitor) { + pyVisitor.visitPyParameterList(this); + } + + @Override + @RequiredReadAction + public PyParameter[] getParameters() { + return getStubOrPsiChildren(PythonDialectsTokenSetProvider.INSTANCE.getParameterTokens(), new PyParameter[0]); + } + + @Override + public void addParameter(PyNamedParameter param) { + PsiElement paren = getLastChild(); + if (paren != null && ")".equals(paren.getText())) { + ASTNode beforeWhat = paren.getNode(); // the closing paren will be this + PyParameter[] params = getParameters(); + boolean hasDefaultValue = param.hasDefaultValue(); + boolean isLast = true; + for (PyParameter p : params) { + if (!hasDefaultValue && p.hasDefaultValue()) { + beforeWhat = p.getNode(); + isLast = false; + break; + } + if (p instanceof PyNamedParameter named) { + if (named.isKeywordContainer() || named.isPositionalContainer()) { + beforeWhat = p.getNode(); + isLast = false; + break; + } + } + } + ASTNode previous = PyPsiUtils.getPrevNonWhitespaceSibling(beforeWhat); + PyUtil.addListNode( + this, + param, + beforeWhat, + !isLast || params.length == 0 || previous.getElementType() == PyTokenTypes.COMMA, + isLast, + beforeWhat.getElementType() != PyTokenTypes.RPAR + ); + } + } + + @Override + @RequiredReadAction + public boolean hasPositionalContainer() { + for (PyParameter parameter : getParameters()) { + if (parameter instanceof PyNamedParameter named && named.isPositionalContainer()) { + return true; + } + } + return false; + } + + @Override + @RequiredReadAction + public boolean hasKeywordContainer() { + for (PyParameter parameter : getParameters()) { + if (parameter instanceof PyNamedParameter named && named.isKeywordContainer()) { + return true; + } + } + return false; + } + + @Override + @Nullable + @RequiredReadAction + public PyNamedParameter findParameterByName(final String name) { + SimpleReference result = new SimpleReference<>(); + ParamHelper.walkDownParamArray( + getParameters(), + new ParamHelper.ParamVisitor() { + @Override + public void visitNamedParameter(PyNamedParameter param, boolean first, boolean last) { + if (name.equals(param.getName())) { + result.set(param); + } + } + } + ); + return result.get(); + } + + @Override + @RequiredReadAction + public LocalizeValue getPresentableText(final boolean includeDefaultValue) { + final StringBuilder target = new StringBuilder(); + final String COMMA = ", "; + target.append("("); + ParamHelper.walkDownParamArray(getParameters(), new ParamHelper.ParamWalker() { + @Override + public void enterTupleParameter(PyTupleParameter param, boolean first, boolean last) { + target.append("("); + } + + @Override + public void leaveTupleParameter(PyTupleParameter param, boolean first, boolean last) { + target.append(")"); + if (!last) { + target.append(COMMA); + } + } + + @Override + public void visitNamedParameter(PyNamedParameter param, boolean first, boolean last) { + target.append(param.getRepr(includeDefaultValue)); + if (!last) { + target.append(COMMA); + } + } + + @Override + public void visitSingleStarParameter(PySingleStarParameter param, boolean first, boolean last) { + target.append('*'); + if (!last) { + target.append(COMMA); + } + } + }); + target.append(")"); + return LocalizeValue.of(target.toString()); + } + + @Nullable + @Override + @RequiredReadAction + public PyFunction getContainingFunction() { + return getParentByStub() instanceof PyFunction f ? f : null; + } + + @Override + @RequiredWriteAction + public void deleteChildInternal(ASTNode node) { + if (ArrayUtil.contains(node.getPsi(), getParameters())) { + PyPsiUtils.deleteAdjacentCommaWithWhitespaces(this, node.getPsi()); + } + super.deleteChildInternal(node); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStarImportElementImpl.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStarImportElementImpl.java index 4dd655a6..59ffb31f 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStarImportElementImpl.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStarImportElementImpl.java @@ -15,9 +15,7 @@ */ package com.jetbrains.python.impl.psi.impl; -import com.google.common.base.Predicate; import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; import com.jetbrains.python.impl.PyElementTypes; import com.jetbrains.python.impl.psi.PyUtil; import com.jetbrains.python.impl.psi.types.PyModuleType; @@ -27,13 +25,16 @@ import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.stubs.PyStarImportElementStub; +import consulo.annotation.access.RequiredReadAction; import consulo.language.ast.ASTNode; import consulo.language.psi.PsiElement; import consulo.language.psi.util.PsiTreeUtil; +import consulo.localize.LocalizeValue; import consulo.navigation.ItemPresentation; import consulo.ui.image.Image; - import org.jspecify.annotations.Nullable; + +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -41,135 +42,105 @@ /** * @author dcheryasov */ -public class PyStarImportElementImpl extends PyBaseElementImpl implements PyStarImportElement -{ - public PyStarImportElementImpl(ASTNode astNode) - { - super(astNode); - } - - public PyStarImportElementImpl(PyStarImportElementStub stub) - { - super(stub, PyElementTypes.STAR_IMPORT_ELEMENT); - } +public class PyStarImportElementImpl extends PyBaseElementImpl implements PyStarImportElement { + public PyStarImportElementImpl(ASTNode astNode) { + super(astNode); + } - public Iterable iterateNames() - { - if(getParent() instanceof PyFromImportStatement) - { - PyFromImportStatement fromImportStatement = (PyFromImportStatement) getParent(); - List importedFiles = fromImportStatement.resolveImportSourceCandidates(); - ChainIterable chain = new ChainIterable<>(); - for(PsiElement importedFile : new HashSet<>(importedFiles)) - { // resolver gives lots of duplicates - PsiElement source = PyUtil.turnDirIntoInit(importedFile); - if(source instanceof PyFile) - { - PyFile sourceFile = (PyFile) source; - chain.add(filterStarImportableNames(sourceFile.iterateNames(), sourceFile)); - } - } - return chain; - } - return Collections.emptyList(); - } + public PyStarImportElementImpl(PyStarImportElementStub stub) { + super(stub, PyElementTypes.STAR_IMPORT_ELEMENT); + } - private static Iterable filterStarImportableNames(Iterable declaredNames, final PyFile file) - { - return Iterables.filter(declaredNames, new Predicate() - { - @Override - public boolean apply(@Nullable PyElement input) - { - String name = input != null ? input.getName() : null; - return name != null && PyUtil.isStarImportableFrom(name, file); - } - }); - } + @Override + @RequiredReadAction + public Iterable iterateNames() { + if (getParent() instanceof PyFromImportStatement fromImportStatement) { + List importedFiles = fromImportStatement.resolveImportSourceCandidates(); + ChainIterable chain = new ChainIterable<>(); + for (PsiElement importedFile : new HashSet<>(importedFiles)) { // resolver gives lots of duplicates + if (PyUtil.turnDirIntoInit(importedFile) instanceof PyFile sourceFile) { + chain.add(filterStarImportableNames(sourceFile.iterateNames(), sourceFile)); + } + } + return chain; + } + return Collections.emptyList(); + } - public List multiResolveName(String name) - { - return PyUtil.getParameterizedCachedValue(this, name, this::calculateMultiResolveName); - } + private static Iterable filterStarImportableNames(Iterable declaredNames, PyFile file) { + return Iterables.filter( + declaredNames, + input -> { + String name = input != null ? input.getName() : null; + return name != null && PyUtil.isStarImportableFrom(name, file); + } + ); + } - private List calculateMultiResolveName(String name) - { - if(PyUtil.isClassPrivateName(name)) - { - return Collections.emptyList(); - } - PsiElement parent = getParentByStub(); - if(parent instanceof PyFromImportStatement) - { - PyFromImportStatement fromImportStatement = (PyFromImportStatement) parent; - List importedFiles = fromImportStatement.resolveImportSourceCandidates(); - for(PsiElement importedFile : new HashSet<>(importedFiles)) - { // resolver gives lots of duplicates - PsiElement source = PyUtil.turnDirIntoInit(importedFile); - if(source instanceof PyFile) - { - PyFile sourceFile = (PyFile) source; - PyModuleType moduleType = new PyModuleType(sourceFile); - List results = moduleType.resolveMember(name, null, AccessDirection.READ, PyResolveContext.defaultContext()); - if(results != null && !results.isEmpty() && PyUtil.isStarImportableFrom(name, sourceFile)) - { - if(results.isEmpty()) - { - return Collections.emptyList(); - } - List res = Lists.newArrayList(); - for(RatedResolveResult result : results) - { - res.add(result); - } - return res; - } - } - } - } - return Collections.emptyList(); - } + @Override + public List multiResolveName(String name) { + return PyUtil.getParameterizedCachedValue(this, name, this::calculateMultiResolveName); + } - @Override - public ItemPresentation getPresentation() - { - return new ItemPresentation() - { + @RequiredReadAction + private List calculateMultiResolveName(String name) { + if (PyUtil.isClassPrivateName(name)) { + return Collections.emptyList(); + } + PsiElement parent = getParentByStub(); + if (parent instanceof PyFromImportStatement fromImportStatement) { + List importedFiles = fromImportStatement.resolveImportSourceCandidates(); + for (PsiElement importedFile : new HashSet<>(importedFiles)) { // resolver gives lots of duplicates + if (PyUtil.turnDirIntoInit(importedFile) instanceof PyFile sourceFile) { + PyModuleType moduleType = new PyModuleType(sourceFile); + List results = + moduleType.resolveMember(name, null, AccessDirection.READ, PyResolveContext.defaultContext()); + if (results != null && !results.isEmpty() && PyUtil.isStarImportableFrom(name, sourceFile)) { + List res = new ArrayList<>(); + for (RatedResolveResult result : results) { + res.add(result); + } + return res; + } + } + } + } + return Collections.emptyList(); + } - private String getName() - { - PyFromImportStatement elt = PsiTreeUtil.getParentOfType(PyStarImportElementImpl.this, PyFromImportStatement.class); - if(elt != null) - { // always? who knows :) - PyReferenceExpression imp_src = elt.getImportSource(); - if(imp_src != null) - { - return PyPsiUtils.toPath(imp_src); - } - } - return ""; - } + @Override + public ItemPresentation getPresentation() { + return new ItemPresentation() { + private String getName() { + PyFromImportStatement elt = PsiTreeUtil.getParentOfType(PyStarImportElementImpl.this, PyFromImportStatement.class); + if (elt != null) { // always? who knows :) + PyReferenceExpression imp_src = elt.getImportSource(); + if (imp_src != null) { + return PyPsiUtils.toPath(imp_src); + } + } + return ""; + } - public String getPresentableText() - { - return getName(); - } + @Override + public LocalizeValue getPresentableText() { + return LocalizeValue.of(getName()); + } - public String getLocationString() - { - return "| " + "from " + getName() + " import *"; - } + @Override + public String getLocationString() { + return "| " + "from " + getName() + " import *"; + } - public Image getIcon() - { - return null; - } - }; - } + @Override + public @Nullable Image getIcon() { + return null; + } + }; + } - @Override - protected void acceptPyVisitor(PyElementVisitor pyVisitor) - { - pyVisitor.visitPyStarImportElement(this); - } + @Override + protected void acceptPyVisitor(PyElementVisitor pyVisitor) { + pyVisitor.visitPyStarImportElement(this); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStringLiteralExpressionImpl.java b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStringLiteralExpressionImpl.java index bbf191e6..242e2a73 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStringLiteralExpressionImpl.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/psi/impl/PyStringLiteralExpressionImpl.java @@ -27,6 +27,7 @@ import consulo.language.ast.IElementType; import consulo.language.psi.*; import consulo.language.psi.util.PsiTreeUtil; +import consulo.localize.LocalizeValue; import consulo.navigation.ItemPresentation; import consulo.platform.base.icon.PlatformIconGroup; import consulo.ui.image.Image; @@ -35,10 +36,8 @@ import java.util.*; import java.util.regex.Matcher; -import java.util.regex.Pattern; public class PyStringLiteralExpressionImpl extends PyElementImpl implements PyStringLiteralExpression { - private enum EscapeRegexGroup { WHOLE_MATCH, ESCAPED_SUBSTRING, @@ -304,11 +303,10 @@ public PsiReference[] getReferences() { @Override public ItemPresentation getPresentation() { return new ItemPresentation() { - @Nullable @Override @RequiredReadAction - public String getPresentableText() { - return getStringValue(); + public LocalizeValue getPresentableText() { + return LocalizeValue.of(getStringValue()); } @Override @@ -316,7 +314,6 @@ public String getLocationString() { return "(" + PyElementPresentation.getPackageForFile(getContainingFile()) + ")"; } - @Nullable @Override public Image getIcon() { return PlatformIconGroup.nodesVariable(); @@ -414,4 +411,5 @@ public boolean isOneLine() { @RequiredReadAction public int valueOffsetToTextOffset(int valueOffset) { return createLiteralTextEscaper().getOffsetInHost(valueOffset, getStringValueTextRange()); - }} + } +} diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/structureView/PyStructureViewElement.java b/python-impl/src/main/java/com/jetbrains/python/impl/structureView/PyStructureViewElement.java index b99c738c..6245aa43 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/structureView/PyStructureViewElement.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/structureView/PyStructureViewElement.java @@ -18,6 +18,7 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; +import consulo.annotation.access.RequiredReadAction; import consulo.codeEditor.CodeInsightColors; import consulo.colorScheme.TextAttributesKey; import consulo.fileEditor.structureView.StructureViewTreeElement; @@ -25,12 +26,14 @@ import consulo.language.icon.IconDescriptorUpdaters; import consulo.language.psi.PsiElement; import consulo.language.psi.util.PsiTreeUtil; +import consulo.localize.LocalizeValue; import consulo.navigation.ItemPresentation; import consulo.ui.ex.ColoredItemPresentation; import consulo.ui.image.Image; import com.jetbrains.python.impl.PythonIcons; import org.jspecify.annotations.Nullable; + import java.util.*; /** @@ -39,252 +42,256 @@ * @author yole */ public class PyStructureViewElement implements StructureViewTreeElement { + protected enum Visibility { + NORMAL, // visible + INVISIBLE, // not visible: e.g. local to function + PRIVATE, // "__foo" in a class + PROTECTED, // "_foo" + PREDEFINED // like "__init__"; only if really visible + } - protected enum Visibility { - NORMAL, // visible - INVISIBLE, // not visible: e.g. local to function - PRIVATE, // "__foo" in a class - PROTECTED, // "_foo" - PREDEFINED // like "__init__"; only if really visible - } - - private PyElement myElement; - private Visibility myVisibility; - private Image myIcon; - private boolean myInherited; - private boolean myField; - - protected PyStructureViewElement(PyElement element, Visibility visibility, boolean inherited, boolean field) { - myElement = element; - myVisibility = visibility; - myInherited = inherited; - myField = field; - } - - public PyStructureViewElement(PyElement element) { - this(element, Visibility.NORMAL, false, false); - } - - protected StructureViewTreeElement createChild(PyElement element, Visibility visibility, boolean inherited, boolean field) { - return new PyStructureViewElement(element, visibility, inherited, field); - } + private PyElement myElement; + private Visibility myVisibility; + private Image myIcon; + private boolean myInherited; + private boolean myField; - @Override - public PyElement getValue() { - return myElement; - } + protected PyStructureViewElement(PyElement element, Visibility visibility, boolean inherited, boolean field) { + myElement = element; + myVisibility = visibility; + myInherited = inherited; + myField = field; + } - public boolean isInherited() { - return myInherited; - } + public PyStructureViewElement(PyElement element) { + this(element, Visibility.NORMAL, false, false); + } - public boolean isField() { - return myField; - } + protected StructureViewTreeElement createChild(PyElement element, Visibility visibility, boolean inherited, boolean field) { + return new PyStructureViewElement(element, visibility, inherited, field); + } - @Override - public void navigate(boolean requestFocus) { - myElement.navigate(requestFocus); - } + @Override + public PyElement getValue() { + return myElement; + } - @Override - public boolean canNavigate() { - return myElement.canNavigate(); - } + public boolean isInherited() { + return myInherited; + } - @Override - public boolean canNavigateToSource() { - return myElement.canNavigateToSource(); - } + public boolean isField() { + return myField; + } - public void setIcon(Image icon) { - myIcon = icon; - } + @Override + @RequiredReadAction + public void navigate(boolean requestFocus) { + myElement.navigate(requestFocus); + } - @Override - public boolean equals(Object o) { - if (o instanceof StructureViewTreeElement) { - Object value = ((StructureViewTreeElement)o).getValue(); - String name = myElement.getName(); - if (value instanceof PyElement && name != null) { - return name.equals(((PyElement)value).getName()); - } + @Override + @RequiredReadAction + public boolean canNavigate() { + return myElement.canNavigate(); } - return false; - } - @Override - public int hashCode() { - String name = myElement.getName(); - return name != null ? name.hashCode() : 0; - } + @Override + @RequiredReadAction + public boolean canNavigateToSource() { + return myElement.canNavigateToSource(); + } - public StructureViewTreeElement[] getChildren() { - Collection children = new ArrayList<>(); - for (PyElement e : getElementChildren(myElement)) { - children.add(createChild(e, getElementVisibility(e), false, elementIsField(e))); + public void setIcon(Image icon) { + myIcon = icon; } - PyPsiUtils.assertValid(myElement); - if (myElement instanceof PyClass) { - for (PyClass c : ((PyClass)myElement).getAncestorClasses(null)) { - for (PyElement e : getElementChildren(c)) { - StructureViewTreeElement inherited = createChild(e, getElementVisibility(e), true, elementIsField(e)); - if (!children.contains(inherited)) { - children.add(inherited); - } + + @Override + public boolean equals(Object o) { + if (o instanceof StructureViewTreeElement) { + Object value = ((StructureViewTreeElement) o).getValue(); + String name = myElement.getName(); + if (value instanceof PyElement && name != null) { + return name.equals(((PyElement) value).getName()); + } } - } + return false; } - return children.toArray(new StructureViewTreeElement[children.size()]); - } - protected boolean elementIsField(PyElement element) { - return element instanceof PyTargetExpression && PsiTreeUtil.getParentOfType(element, PyClass.class) != null; - } - - private static Visibility getElementVisibility(PyElement element) { - if (!(element instanceof PyTargetExpression) && PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) { - return Visibility.INVISIBLE; - } - else { - return getVisibilityByName(element.getName()); + @Override + public int hashCode() { + String name = myElement.getName(); + return name != null ? name.hashCode() : 0; } - } - private Collection getElementChildren(final PyElement element) { - final Collection children = new ArrayList<>(); - PyPsiUtils.assertValid(element); - element.acceptChildren(new PyElementVisitor() { - @Override - public void visitElement(PsiElement e) { - if (isWorthyItem(e, element)) { - children.add((PyElement)e); + @Override + @RequiredReadAction + public StructureViewTreeElement[] getChildren() { + Collection children = new ArrayList<>(); + for (PyElement e : getElementChildren(myElement)) { + children.add(createChild(e, getElementVisibility(e), false, elementIsField(e))); } - else { - e.acceptChildren(this); - } - } - }); - if (element instanceof PyClass) { - List attrs = getClassAttributes((PyClass)element); - List filtered = new ArrayList<>(); - Set names = new HashSet<>(); - for (PyElement attr : attrs) { - String name = attr.getName(); - PyPsiUtils.assertValid(attr); - if (!names.contains(name)) { - filtered.add(attr); + PyPsiUtils.assertValid(myElement); + if (myElement instanceof PyClass) { + for (PyClass c : ((PyClass) myElement).getAncestorClasses(null)) { + for (PyElement e : getElementChildren(c)) { + StructureViewTreeElement inherited = createChild(e, getElementVisibility(e), true, elementIsField(e)); + if (!children.contains(inherited)) { + children.add(inherited); + } + } + } } - names.add(name); - } - Comparator comparator = (e1, e2) -> { - String n1 = e1.getName(); - String n2 = e2.getName(); - return (n1 != null && n2 != null) ? n1.compareTo(n2) : 0; - }; - Collections.sort(filtered, comparator); - children.addAll(filtered); + return children.toArray(new StructureViewTreeElement[children.size()]); } - return children; - } - protected List getClassAttributes(PyClass cls) { - List results = new ArrayList<>(); - results.addAll(cls.getInstanceAttributes()); - results.addAll(cls.getClassAttributes()); - return results; - } + protected boolean elementIsField(PyElement element) { + return element instanceof PyTargetExpression && PsiTreeUtil.getParentOfType(element, PyClass.class) != null; + } - private static Visibility getVisibilityByName(@Nullable String name) { - if (name != null) { - if (name.startsWith("__")) { - if (PyNames.UnderscoredAttributes.contains(name)) { - return Visibility.PREDEFINED; + private static Visibility getElementVisibility(PyElement element) { + if (!(element instanceof PyTargetExpression) && PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) { + return Visibility.INVISIBLE; } else { - return Visibility.PRIVATE; + return getVisibilityByName(element.getName()); } - } - else if (name.startsWith("_")) { - return Visibility.PROTECTED; - } } - return Visibility.NORMAL; - } - protected boolean isWorthyItem(@Nullable PsiElement element, @Nullable PsiElement parent) { - if (element instanceof PyClass || element instanceof PyFunction) { - return true; - } - if (!(parent instanceof PyClass) && (element instanceof PyTargetExpression) && !((PyTargetExpression)element).isQualified()) { - PsiElement e = element.getParent(); - if (e instanceof PyAssignmentStatement) { - e = e.getParent(); - if (e instanceof PyFile) { - return true; + @RequiredReadAction + private Collection getElementChildren(final PyElement element) { + final Collection children = new ArrayList<>(); + PyPsiUtils.assertValid(element); + element.acceptChildren(new PyElementVisitor() { + @Override + public void visitElement(PsiElement e) { + if (isWorthyItem(e, element)) { + children.add((PyElement) e); + } + else { + e.acceptChildren(this); + } + } + }); + if (element instanceof PyClass) { + List attrs = getClassAttributes((PyClass) element); + List filtered = new ArrayList<>(); + Set names = new HashSet<>(); + for (PyElement attr : attrs) { + String name = attr.getName(); + PyPsiUtils.assertValid(attr); + if (!names.contains(name)) { + filtered.add(attr); + } + names.add(name); + } + Comparator comparator = (e1, e2) -> { + String n1 = e1.getName(); + String n2 = e2.getName(); + return (n1 != null && n2 != null) ? n1.compareTo(n2) : 0; + }; + Collections.sort(filtered, comparator); + children.addAll(filtered); } - } + return children; } - return false; - } - @Override - public ItemPresentation getPresentation() { - final ItemPresentation presentation = myElement.getPresentation(); - return new ColoredItemPresentation() { - @Nullable - @Override - public String getPresentableText() { - if (myElement instanceof PyFile) { - return myElement.getName(); - } - return presentation != null ? presentation.getPresentableText() : PyNames.UNNAMED_ELEMENT; - } + protected List getClassAttributes(PyClass cls) { + List results = new ArrayList<>(); + results.addAll(cls.getInstanceAttributes()); + results.addAll(cls.getClassAttributes()); + return results; + } - @Nullable - @Override - public TextAttributesKey getTextAttributesKey() { - if (isInherited()) { - return CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES; + private static Visibility getVisibilityByName(@Nullable String name) { + if (name != null) { + if (name.startsWith("__")) { + if (PyNames.UnderscoredAttributes.contains(name)) { + return Visibility.PREDEFINED; + } + else { + return Visibility.PRIVATE; + } + } + else if (name.startsWith("_")) { + return Visibility.PROTECTED; + } } - return null; - } - - @Nullable - @Override - public String getLocationString() { - return null; - } + return Visibility.NORMAL; + } - @Nullable - @Override - public Image getIcon() { - Image normal_icon = IconDescriptorUpdaters.getIcon(myElement, 0); - if (myIcon != null) { - normal_icon = myIcon; // override normal + protected boolean isWorthyItem(@Nullable PsiElement element, @Nullable PsiElement parent) { + if (element instanceof PyClass || element instanceof PyFunction) { + return true; } - if (myVisibility == Visibility.NORMAL) { - return normal_icon; + if (!(parent instanceof PyClass) && element instanceof PyTargetExpression target && !target.isQualified()) { + PsiElement e = element.getParent(); + if (e instanceof PyAssignmentStatement assignment) { + e = assignment.getParent(); + if (e instanceof PyFile) { + return true; + } + } } - else { - IconDescriptor iconDescriptor = new IconDescriptor(normal_icon); + return false; + } - Image overlay = null; - if (myVisibility == Visibility.PRIVATE || myVisibility == Visibility.PROTECTED) { - overlay = PythonIcons.Python.Nodes.Lock; - } - else if (myVisibility == Visibility.PREDEFINED) { - overlay = PythonIcons.Python.Nodes.Cyan_dot; - } - else if (myVisibility == Visibility.INVISIBLE) { - overlay = PythonIcons.Python.Nodes.Red_inv_triangle; - } - if (overlay != null) { - iconDescriptor.addLayerIcon(overlay); - } - return iconDescriptor.toIcon(); - } - } - }; - } + @Override + public ItemPresentation getPresentation() { + final ItemPresentation presentation = myElement.getPresentation(); + return new ColoredItemPresentation() { + @Override + public LocalizeValue getPresentableText() { + if (myElement instanceof PyFile) { + return LocalizeValue.ofNullable(myElement.getName()); + } + return presentation != null ? presentation.getPresentableText() : PyNames.UNNAMED_ELEMENT; + } + + @Nullable + @Override + public TextAttributesKey getTextAttributesKey() { + if (isInherited()) { + return CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES; + } + return null; + } + + @Nullable + @Override + public String getLocationString() { + return null; + } + + @Override + @RequiredReadAction + public Image getIcon() { + Image normalIcon = IconDescriptorUpdaters.getIcon(myElement, 0); + if (myIcon != null) { + normalIcon = myIcon; // override normal + } + if (myVisibility == Visibility.NORMAL) { + return normalIcon; + } + else { + IconDescriptor iconDescriptor = new IconDescriptor(normalIcon); + + Image overlay = null; + if (myVisibility == Visibility.PRIVATE || myVisibility == Visibility.PROTECTED) { + overlay = PythonIcons.Python.Nodes.Lock; + } + else if (myVisibility == Visibility.PREDEFINED) { + overlay = PythonIcons.Python.Nodes.Cyan_dot; + } + else if (myVisibility == Visibility.INVISIBLE) { + overlay = PythonIcons.Python.Nodes.Red_inv_triangle; + } + if (overlay != null) { + iconDescriptor.addLayerIcon(overlay); + } + return iconDescriptor.toIcon(); + } + } + }; + } } diff --git a/python-psi-api/src/main/java/com/jetbrains/python/PyNames.java b/python-psi-api/src/main/java/com/jetbrains/python/PyNames.java index a67f666e..eb891101 100644 --- a/python-psi-api/src/main/java/com/jetbrains/python/PyNames.java +++ b/python-psi-api/src/main/java/com/jetbrains/python/PyNames.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap; import com.jetbrains.python.psi.LanguageLevel; +import consulo.localize.LocalizeValue; import org.jspecify.annotations.Nullable; import java.util.*; import java.util.regex.Pattern; @@ -205,7 +206,7 @@ private PyNames() { public static final String UNKNOWN_TYPE = "Any"; - public static final String UNNAMED_ELEMENT = ""; + public static final LocalizeValue UNNAMED_ELEMENT = LocalizeValue.localizeTODO(""); /** * Contains all known predefined names of "__foo__" form. diff --git a/python-psi-api/src/main/java/com/jetbrains/python/psi/PyParameterList.java b/python-psi-api/src/main/java/com/jetbrains/python/psi/PyParameterList.java index 4764d449..c7fc817a 100644 --- a/python-psi-api/src/main/java/com/jetbrains/python/psi/PyParameterList.java +++ b/python-psi-api/src/main/java/com/jetbrains/python/psi/PyParameterList.java @@ -13,51 +13,49 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.jetbrains.python.psi; - import consulo.language.psi.StubBasedPsiElement; import com.jetbrains.python.psi.stubs.PyParameterListStub; +import consulo.localize.LocalizeValue; import org.jspecify.annotations.Nullable; /** * Represents function parameter list. - * Date: 29.05.2005 + * @since 2005-05-29 */ public interface PyParameterList extends PyElement, StubBasedPsiElement { - - /** - * Extracts the individual parameters. - * Note that tuple parameters are flattened by this method. - * @return a possibly empty array of named paramaters. - */ - PyParameter[] getParameters(); - - @Nullable - PyNamedParameter findParameterByName(String name); - - - /** - * Adds a paramter to list, after all other parameters. - * @param param what to add - */ - void addParameter(PyNamedParameter param); - - - /** - * @return true iff this list contains an '*args'-type parameter. - */ - boolean hasPositionalContainer(); - - /** - * @return true iff this list contains a '**kwargs'-type parameter. - */ - boolean hasKeywordContainer(); - - String getPresentableText(boolean includeDefaultValue); - - @Nullable - PyFunction getContainingFunction(); + /** + * Extracts the individual parameters. + * Note that tuple parameters are flattened by this method. + * + * @return a possibly empty array of named parameters. + */ + PyParameter[] getParameters(); + + @Nullable + PyNamedParameter findParameterByName(String name); + + /** + * Adds a parameter to list, after all other parameters. + * + * @param param what to add + */ + void addParameter(PyNamedParameter param); + + /** + * @return true iff this list contains an '*args'-type parameter. + */ + boolean hasPositionalContainer(); + + /** + * @return true iff this list contains a '**kwargs'-type parameter. + */ + boolean hasKeywordContainer(); + + LocalizeValue getPresentableText(boolean includeDefaultValue); + + @Nullable + PyFunction getContainingFunction(); }