From 50d1e9b3cc2e3b588790b4009903602d73e70874 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 23 Jan 2014 22:00:58 +0400 Subject: [PATCH] Cleanup of API for qualified names of expressions Added PyQualifiedExpression.asQualifiedName() and moved utility functions to PyPsiUtils. Expression classes can now cache the results of calculating their qualified names. --- .../python/psi/PyQualifiedExpression.java | 7 +++ .../python/psi/PyReferenceExpression.java | 5 -- .../jetbrains/python/psi/impl/PyPsiUtils.java | 61 +++++++++++++++++++ .../psi/impl/PyQualifiedNameFactory.java | 48 --------------- .../ImportFromToImportIntention.java | 8 +-- .../ImportToImportFromIntention.java | 8 +-- .../ImportToggleAliasIntention.java | 6 +- .../PyPackageRequirementsInspection.java | 7 +-- .../psi/impl/PyBinaryExpressionImpl.java | 7 +++ .../python/psi/impl/PyClassImpl.java | 2 +- .../python/psi/impl/PyDecoratorImpl.java | 11 +--- .../python/psi/impl/PyImportElementImpl.java | 9 +-- .../psi/impl/PyPrefixExpressionImpl.java | 7 +++ .../psi/impl/PyReferenceExpressionImpl.java | 2 +- .../psi/impl/PyStarImportElementImpl.java | 3 +- .../impl/PySubscriptionExpressionImpl.java | 7 +++ .../psi/impl/PyTargetExpressionImpl.java | 11 +++- .../impl/references/PyQualifiedReference.java | 3 +- .../psi/impl/stubs/PyClassElementType.java | 5 +- .../resolve/AssignmentCollectProcessor.java | 12 ++-- .../python/psi/resolve/PyResolveUtil.java | 48 --------------- 21 files changed, 126 insertions(+), 151 deletions(-) delete mode 100644 python/psi-api/src/com/jetbrains/python/psi/impl/PyQualifiedNameFactory.java diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java index 48927bbb1d70..995ad30895cf 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java @@ -17,6 +17,7 @@ package com.jetbrains.python.psi; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiPolyVariantReference; +import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.resolve.PyResolveContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +38,12 @@ public interface PyQualifiedExpression extends PyExpression { */ boolean isQualified(); + /** + * Returns the qualified name for the expression if all the qualifiers are qualified expressions. + */ + @Nullable + QualifiedName asQualifiedName(); + /** * Returns the name to the right of the qualifier. * diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java index a8fd0a98ad82..c1f7e8d63b87 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java @@ -16,11 +16,9 @@ package com.jetbrains.python.psi; import com.intellij.psi.PsiPolyVariantReference; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.QualifiedResolveResult; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * @author yole @@ -40,9 +38,6 @@ public interface PyReferenceExpression extends PyQualifiedExpression, PyReferenc @NotNull QualifiedResolveResult followAssignmentsChain(PyResolveContext resolveContext); - @Nullable - QualifiedName asQualifiedName(); - @NotNull PsiPolyVariantReference getReference(); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java index c8433aa14298..b3a1134a2e03 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java +++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java @@ -23,6 +23,7 @@ import com.intellij.psi.*; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.QualifiedName; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyTokenTypes; @@ -32,6 +33,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; /** @@ -375,6 +377,65 @@ public class PyPsiUtils { return element.getTextOffset() <= element2.getTextOffset(); } + @Nullable + public static QualifiedName asQualifiedName(@Nullable PyExpression expr) { + return expr instanceof PyQualifiedExpression ? ((PyQualifiedExpression)expr).asQualifiedName() : null; + } + + @Nullable + public static PyExpression getFirstQualifier(@NotNull PyQualifiedExpression expr) { + final List expressions = unwindQualifiers(expr); + if (!expressions.isEmpty()) { + return expressions.get(0); + } + return null; + } + + @NotNull + public static String toPath(@Nullable PyQualifiedExpression expr) { + if (expr != null) { + final QualifiedName qName = expr.asQualifiedName(); + if (qName != null) { + return qName.toString(); + } + final String name = expr.getName(); + if (name != null) { + return name; + } + } + return ""; + } + + @Nullable + protected static QualifiedName asQualifiedName(@NotNull PyQualifiedExpression expr) { + return fromReferenceChain(unwindQualifiers(expr)); + } + + @NotNull + private static List unwindQualifiers(@NotNull final PyQualifiedExpression expr) { + final List path = new LinkedList(); + PyQualifiedExpression e = expr; + while (e != null) { + path.add(0, e); + final PyExpression q = e.getQualifier(); + e = q instanceof PyQualifiedExpression ? (PyQualifiedExpression)q : null; + } + return path; + } + + @Nullable + private static QualifiedName fromReferenceChain(@NotNull List components) { + final List componentNames = new ArrayList(components.size()); + for (PyExpression component : components) { + final String refName = (component instanceof PyQualifiedExpression) ? ((PyQualifiedExpression)component).getReferencedName() : null; + if (refName == null) { + return null; + } + componentNames.add(refName); + } + return QualifiedName.fromComponents(componentNames); + } + private static abstract class TopLevelVisitor extends PyRecursiveElementVisitor { public void visitPyElement(final PyElement node) { super.visitPyElement(node); diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyQualifiedNameFactory.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyQualifiedNameFactory.java deleted file mode 100644 index b26d4451cb02..000000000000 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyQualifiedNameFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jetbrains.python.psi.impl; - -import com.intellij.psi.util.QualifiedName; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyQualifiedExpression; -import com.jetbrains.python.psi.PyReferenceExpression; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author yole - */ -public class PyQualifiedNameFactory { - @Nullable - public static QualifiedName fromReferenceChain(List components) { - List componentNames = new ArrayList(components.size()); - for (PyExpression component : components) { - final String refName = (component instanceof PyQualifiedExpression) ? ((PyQualifiedExpression)component).getReferencedName() : null; - if (refName == null) { - return null; - } - componentNames.add(refName); - } - return QualifiedName.fromComponents(componentNames); - } - - @Nullable - public static QualifiedName fromExpression(PyExpression expr) { - return expr instanceof PyReferenceExpression ? ((PyReferenceExpression) expr).asQualifiedName() : null; - } -} diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java index 1b4a7c0012a6..0170b8b53e5a 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java @@ -28,7 +28,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashMap; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveUtil; +import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.types.PyModuleType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; @@ -84,7 +84,7 @@ public class ImportFromToImportIntention implements IntentionAction { ret.myModuleReference = ret.myFromImportStatement.getImportSource(); } if (ret.myModuleReference != null) { - ret.myModuleName = PyResolveUtil.toPath(ret.myModuleReference); + ret.myModuleName = PyPsiUtils.toPath(ret.myModuleReference); } return ret; } @@ -117,7 +117,7 @@ public class ImportFromToImportIntention implements IntentionAction { if (info.myModuleReference != null) { PyExpression remaining_module = info.myModuleReference.getQualifier(); if (remaining_module instanceof PyQualifiedExpression) { - remaining_name = PyResolveUtil.toPath((PyQualifiedExpression)remaining_module); + remaining_name = PyPsiUtils.toPath((PyQualifiedExpression)remaining_module); } else remaining_name = ""; // unqualified name: "...module" separated_name = info.myModuleReference.getReferencedName(); @@ -169,7 +169,7 @@ public class ImportFromToImportIntention implements IntentionAction { } } if (info.myModuleReference != null) { - info.myModuleName = PyResolveUtil.toPath(info.myModuleReference); + info.myModuleName = PyPsiUtils.toPath(info.myModuleReference); } if (info.myModuleReference != null && info.myModuleName != null && info.myFromImportStatement != null) { myText = info.getText(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java index 453c28951c8e..fc35833473f8 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java @@ -30,7 +30,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveUtil; +import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -94,7 +94,7 @@ public class ImportToImportFromIntention implements IntentionAction { // usages of imported name are qualifiers; what they refer to? PyReferenceExpression reference = myImportElement.getImportReferenceExpression(); if (reference != null) { - myModuleName = PyResolveUtil.toPath(reference); + myModuleName = PyPsiUtils.toPath(reference); myQualifierName = myImportElement.getVisibleName(); myReferee = reference.getReference().resolve(); myHasModuleReference = false; @@ -104,7 +104,7 @@ public class ImportToImportFromIntention implements IntentionAction { public boolean execute(@NotNull PsiElement element) { if (element instanceof PyReferenceExpression && PsiTreeUtil.getParentOfType(element, PyImportElement.class) == null) { PyReferenceExpression ref = (PyReferenceExpression)element; - if (myQualifierName.equals(PyResolveUtil.toPath(ref))) { // filter out other names that might resolve to our target + if (myQualifierName.equals(PyPsiUtils.toPath(ref))) { // filter out other names that might resolve to our target PsiElement parent_elt = ref.getParent(); if (parent_elt instanceof PyQualifiedExpression) { // really qualified by us, not just referencing? PsiElement resolved = ref.getReference().resolve(); @@ -197,7 +197,7 @@ public class ImportToImportFromIntention implements IntentionAction { String module_name = "?"; if (myImportElement != null) { PyReferenceExpression reference = myImportElement.getImportReferenceExpression(); - if (reference != null) module_name = PyResolveUtil.toPath(reference); + if (reference != null) module_name = PyPsiUtils.toPath(reference); } return PyBundle.message("INTN.convert.to.from.$0.import.$1", getDots()+module_name, "..."); } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java index 6b79d2104f44..621adf8cda3e 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java @@ -38,7 +38,7 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveUtil; +import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -136,7 +136,7 @@ public class ImportToggleAliasIntention implements IntentionAction { PyReferenceExpression reference = sure(state.myImportElement.getImportReferenceExpression()); // search for references to us with the right name try { - String imported_name = PyResolveUtil.toPath(reference); + String imported_name = PyPsiUtils.toPath(reference); if (state.myAlias != null) { // have to remove alias, rename everything to original target_name = imported_name; @@ -201,7 +201,7 @@ public class ImportToggleAliasIntention implements IntentionAction { if (element instanceof PyReferenceExpression && PsiTreeUtil.getParentOfType(element, PyImportElement.class) == null) { PyReferenceExpression ref = (PyReferenceExpression)element; - if (remove_name.equals(PyResolveUtil.toPath(ref))) { // filter out other names that might resolve to our target + if (remove_name.equals(PyPsiUtils.toPath(ref))) { // filter out other names that might resolve to our target PsiElement resolved = ref.getReference().resolve(); if (resolved == referee) references.add(ref.getReference()); } diff --git a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java index 5a3bdce3059a..ec3761154f28 100644 --- a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java @@ -41,7 +41,7 @@ import com.jetbrains.python.codeInsight.stdlib.PyStdlibUtil; import com.jetbrains.python.packaging.*; import com.jetbrains.python.packaging.ui.PyChooseRequirementsDialog; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveUtil; +import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -147,9 +147,8 @@ public class PyPackageRequirementsInspection extends PyInspection { return; } } - final List expressions = PyResolveUtil.unwindQualifiers(importedExpression); - if (!expressions.isEmpty()) { - final PyExpression packageReferenceExpression = expressions.get(0); + final PyExpression packageReferenceExpression = PyPsiUtils.getFirstQualifier(importedExpression); + if (packageReferenceExpression != null) { final String packageName = packageReferenceExpression.getName(); if (packageName != null && !myIgnoredPackages.contains(packageName)) { if (!ApplicationManager.getApplication().isUnitTestMode() && !PyPIPackageUtil.INSTANCE.isInPyPI(packageName)) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java index 0948536d4d23..bee876ac948d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.QualifiedName; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyNames; @@ -152,6 +153,12 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp return getLeftExpression(); } + @Nullable + @Override + public QualifiedName asQualifiedName() { + return PyPsiUtils.asQualifiedName(this); + } + @Override public boolean isQualified() { return getQualifier() != null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 11af8344f708..877e5fbc883a 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -1183,7 +1183,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement } else { final PyClassStub stub = getStub(); - final QualifiedName name = stub != null ? stub.getMetaClass() : PyQualifiedNameFactory.fromExpression(getMetaClassExpression()); + final QualifiedName name = stub != null ? stub.getMetaClass() : PyPsiUtils.asQualifiedName(getMetaClassExpression()); final PsiFile file = getContainingFile(); if (file instanceof PyFile) { final PyFile pyFile = (PyFile)file; diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java index f64b533f3303..48d7e022ddda 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java @@ -26,7 +26,6 @@ import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; -import com.jetbrains.python.psi.resolve.PyResolveUtil; import com.jetbrains.python.psi.stubs.PyDecoratorStub; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; @@ -34,8 +33,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - /** * @author dcheryasov */ @@ -84,13 +81,9 @@ public class PyDecoratorImpl extends StubBasedPsiElementBase im return stub.getQualifiedName(); } else { - PyReferenceExpression node = PsiTreeUtil.getChildOfType(this, PyReferenceExpression.class); + final PyReferenceExpression node = PsiTreeUtil.getChildOfType(this, PyReferenceExpression.class); if (node != null) { - List parts = PyResolveUtil.unwindQualifiers(node); - if (parts != null) { - //Collections.reverse(parts); - return PyQualifiedNameFactory.fromReferenceChain(parts); - } + return node.asQualifiedName(); } return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java index ddeaf120451a..70e3ecf44e9b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java @@ -28,7 +28,6 @@ import com.intellij.util.containers.EmptyIterable; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveUtil; import com.jetbrains.python.psi.resolve.ResolveImportUtil; import com.jetbrains.python.psi.stubs.PyImportElementStub; import org.jetbrains.annotations.NotNull; @@ -36,7 +35,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Collections; -import java.util.List; /** * The "import foo" or "import foo as bar" parts. @@ -150,7 +148,7 @@ public class PyImportElementImpl extends PyBaseElementImpl buf.append("from "); PyReferenceExpression imp_src = ((PyFromImportStatement)elt).getImportSource(); if (imp_src != null) { - buf.append(PyResolveUtil.toPath(imp_src)); + buf.append(PyPsiUtils.toPath(imp_src)); } else { buf.append(""); @@ -185,10 +183,7 @@ public class PyImportElementImpl extends PyBaseElementImpl if (ret == null) { final PyReferenceExpression importReference = getImportReferenceExpression(); if (importReference != null) { - final List qualifiers = PyResolveUtil.unwindQualifiers(importReference); - if (qualifiers.size() > 0) { - ret = qualifiers.get(0); - } + ret = PyPsiUtils.getFirstQualifier(importReference); } } if (ret == null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java index bbd4b1115095..71658f075451 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; +import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; @@ -98,6 +99,12 @@ public class PyPrefixExpressionImpl extends PyElementImpl implements PyPrefixExp return getOperand(); } + @Nullable + @Override + public QualifiedName asQualifiedName() { + return PyPsiUtils.asQualifiedName(this); + } + @Override public boolean isQualified() { return getQualifier() != null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 111efa05698f..1a39caabf339 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -181,7 +181,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere @Nullable public QualifiedName asQualifiedName() { if (myQualifiedName == null) { - myQualifiedName = PyQualifiedNameFactory.fromReferenceChain(PyResolveUtil.unwindQualifiers(this)); + myQualifiedName = PyPsiUtils.asQualifiedName(this); } return myQualifiedName; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java index a30a2de545bd..307ac8e22841 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java @@ -22,7 +22,6 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.HashSet; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; -import com.jetbrains.python.psi.resolve.PyResolveUtil; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.PyModuleType; import com.jetbrains.python.toolbox.ChainIterable; @@ -101,7 +100,7 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo if (elt != null) { // always? who knows :) PyReferenceExpression imp_src = elt.getImportSource(); if (imp_src != null) { - return PyResolveUtil.toPath(imp_src); + return PyPsiUtils.toPath(imp_src); } } return ""; diff --git a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java index 01feab373a86..61438286bb8b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; +import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; @@ -107,6 +108,12 @@ public class PySubscriptionExpressionImpl extends PyElementImpl implements PySub return getOperand(); } + @Nullable + @Override + public QualifiedName asQualifiedName() { + return PyPsiUtils.asQualifiedName(this); + } + @Override public boolean isQualified() { return getQualifier() != null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 75108f977084..94292fd4ee6f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -60,6 +60,7 @@ import java.util.List; * @author yole */ public class PyTargetExpressionImpl extends PyPresentableElementImpl implements PyTargetExpression { + public PyTargetExpressionImpl(ASTNode astNode) { super(astNode); } @@ -463,6 +464,12 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl collectAssignedAttributes(PyQualifiedExpression qualifier) { - QualifiedName qualifierPath = PyQualifiedNameFactory.fromReferenceChain(PyResolveUtil.unwindQualifiers(qualifier)); + final QualifiedName qualifierPath = qualifier.asQualifiedName(); if (qualifierPath != null) { AssignmentCollectProcessor proc = new AssignmentCollectProcessor(qualifierPath); PyResolveUtil.treeCrawlUp(proc, qualifier); diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java index e29c71c092be..e3d399c2d50b 100644 --- a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java +++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java @@ -24,7 +24,6 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyClassImpl; import com.jetbrains.python.psi.impl.PyPsiUtils; import com.intellij.psi.util.QualifiedName; -import com.jetbrains.python.psi.impl.PyQualifiedNameFactory; import com.jetbrains.python.psi.stubs.PyClassNameIndex; import com.jetbrains.python.psi.stubs.PyClassNameIndexInsensitive; import com.jetbrains.python.psi.stubs.PyClassStub; @@ -63,12 +62,12 @@ public class PyClassElementType extends PyStubElementType continue; } expression = PyClassImpl.unfoldClass(expression); - superClasses.add(PyQualifiedNameFactory.fromExpression(expression)); + superClasses.add(PyPsiUtils.asQualifiedName(expression)); } final PyStringLiteralExpression docStringExpression = psi.getDocStringExpression(); return new PyClassStubImpl(psi.getName(), parentStub, superClasses.toArray(new QualifiedName[superClasses.size()]), - PyQualifiedNameFactory.fromExpression(psi.getMetaClassExpression()), + PyPsiUtils.asQualifiedName(psi.getMetaClassExpression()), psi.getOwnSlots(), PyPsiUtils.strValue(docStringExpression), getStubElementType()); diff --git a/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java b/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java index 0dde3952e9c1..1f02473d5632 100644 --- a/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java +++ b/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java @@ -19,11 +19,10 @@ import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; import com.intellij.psi.ResolveState; import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.PyAssignmentStatement; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyTargetExpression; -import com.intellij.psi.util.QualifiedName; -import com.jetbrains.python.psi.impl.PyQualifiedNameFactory; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -56,15 +55,12 @@ public class AssignmentCollectProcessor implements PsiScopeProcessor { for (PyExpression ex : assignment.getTargets()) { if (ex instanceof PyTargetExpression) { final PyTargetExpression target = (PyTargetExpression)ex; - List qualsExpr = PyResolveUtil.unwindQualifiers(target); - QualifiedName qualifiedName = PyQualifiedNameFactory.fromReferenceChain(qualsExpr); + final QualifiedName qualifiedName = target.asQualifiedName(); if (qualifiedName != null) { if (qualifiedName.getComponentCount() == myQualifier.getComponentCount() + 1 && qualifiedName.matchesPrefix(myQualifier)) { - // a new attribute follows last qualifier; collect it. - PyExpression last_elt = qualsExpr.get(qualsExpr.size() - 1); // last item is the outermost, new, attribute. - String last_elt_name = last_elt.getName(); + String last_elt_name = target.getName(); if (!mySeenNames.contains(last_elt_name)) { // no dupes, only remember the latest - myResult.add(last_elt); + myResult.add(target); mySeenNames.add(last_elt_name); } } diff --git a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java index acf07599bc35..da8c0d618a8b 100644 --- a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java @@ -35,14 +35,9 @@ import com.jetbrains.python.codeInsight.dataflow.scope.Scope; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; -import com.intellij.psi.util.QualifiedName; -import com.jetbrains.python.psi.impl.PyQualifiedNameFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.LinkedList; -import java.util.List; - /** * Ref resolution routines. * User: dcheryasov @@ -246,49 +241,6 @@ public class PyResolveUtil { return false; } - /** - * Unwinds a multi-level qualified expression into a path, as seen in source text, i.e. outermost qualifier first. - * - * @param expr an expression to unwind. - * @return path as a list of ref expressions. - */ - @NotNull - public static List unwindQualifiers(@NotNull final PyQualifiedExpression expr) { - final List path = new LinkedList(); - PyQualifiedExpression e = expr; - while (e != null) { - path.add(0, e); - final PyExpression q = e.getQualifier(); - e = q instanceof PyQualifiedExpression ? (PyQualifiedExpression)q : null; - } - return path; - } - - public static List unwindQualifiersAsStrList(final PyQualifiedExpression expr) { - final List path = new LinkedList(); - PyQualifiedExpression e = expr; - while (e != null) { - path.add(0, e.getText()); - final PyExpression q = e.getQualifier(); - e = q instanceof PyQualifiedExpression ? (PyQualifiedExpression)q : null; - } - return path; - } - - public static String toPath(PyQualifiedExpression expr) { - if (expr == null) return ""; - List path = unwindQualifiers(expr); - final QualifiedName qName = PyQualifiedNameFactory.fromReferenceChain(path); - if (qName != null) { - return qName.toString(); - } - String name = expr.getName(); - if (name != null) { - return name; - } - return ""; - } - /** * Accepts only targets that are not the given object. */