mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merging PyQualifiedName.toString()
This commit is contained in:
@@ -333,6 +333,5 @@
|
||||
text="Run Django Console..." description="Allows to quickly run Django console">
|
||||
<add-to-group group-id="ToolsMenu" anchor="last"/>
|
||||
</action>
|
||||
<action id="Console.Execute" class="com.intellij.openapi.actionSystem.EmptyAction" text="Execute Current Statement"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -24,6 +24,7 @@ public class PyCodeInsightSettings implements PersistentStateComponent<PyCodeIns
|
||||
|
||||
public boolean PREFER_FROM_IMPORT = true;
|
||||
public boolean SHOW_IMPORT_POPUP = true;
|
||||
public boolean HIGHLIGHT_UNUSED_IMPORTS = true;
|
||||
|
||||
public PyCodeInsightSettings getState() {
|
||||
return this;
|
||||
|
||||
@@ -93,7 +93,9 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
|
||||
public void inspectionFinished(LocalInspectionToolSession session) {
|
||||
final Visitor visitor = myLastVisitor.get();
|
||||
assert visitor != null;
|
||||
visitor.highlightUnusedImports();
|
||||
if (PyCodeInsightSettings.getInstance().HIGHLIGHT_UNUSED_IMPORTS) {
|
||||
visitor.highlightUnusedImports();
|
||||
}
|
||||
myLastVisitor.remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,10 @@ public class PyImportElementImpl extends PyBaseElementImpl<PyImportElementStub>
|
||||
if (qName == null || qName.getComponentCount() == 0 || !qName.getComponents().get(0).equals(the_name)) {
|
||||
return null;
|
||||
}
|
||||
return ResolveImportUtil.resolveImportElement(this, PyQualifiedName.fromComponents(the_name));
|
||||
if (qName.getComponentCount() == 1) {
|
||||
return ResolveImportUtil.resolveImportElement(this, PyQualifiedName.fromComponents(the_name));
|
||||
}
|
||||
return new PyImportedModule((PyFile) getContainingFile(), PyQualifiedName.fromComponents(the_name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.impl.light.LightElement;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.psi.NameDefiner;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyImportElement;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.ResolveImportUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -25,6 +24,14 @@ public class PyImportedModule extends LightElement implements NameDefiner {
|
||||
myImportedPrefix = importedPrefix;
|
||||
}
|
||||
|
||||
public PyFile getContainingFile() {
|
||||
return myContainingFile;
|
||||
}
|
||||
|
||||
public PyQualifiedName getImportedPrefix() {
|
||||
return myImportedPrefix;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterable<PyElement> iterateNames() {
|
||||
throw new UnsupportedOperationException();
|
||||
@@ -32,29 +39,27 @@ public class PyImportedModule extends LightElement implements NameDefiner {
|
||||
|
||||
public PsiElement getElementNamed(String the_name) {
|
||||
PyQualifiedName prefix = myImportedPrefix.append(the_name);
|
||||
final List<PyImportElement> imports = ((PyFileImpl)myContainingFile).getImportTargets();
|
||||
for (PyImportElement anImport : imports) {
|
||||
final PyQualifiedName qName = anImport.getImportedQName();
|
||||
if (qName != null && matchesPrefix(qName, prefix)) {
|
||||
if (qName.getComponentCount() == prefix.getComponentCount()) {
|
||||
return anImport;
|
||||
}
|
||||
return new PyImportedModule(myContainingFile, prefix);
|
||||
final PyImportElement importElement = findMatchingImportElement(prefix);
|
||||
if (importElement != null) {
|
||||
final PyQualifiedName qName = importElement.getImportedQName();
|
||||
if (qName != null && qName.getComponentCount() == prefix.getComponentCount()) {
|
||||
return resolve(importElement, prefix);
|
||||
}
|
||||
return new PyImportedModule(myContainingFile, prefix);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean matchesPrefix(PyQualifiedName qName, PyQualifiedName prefix) {
|
||||
if (qName.getComponentCount() < prefix.getComponentCount()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < prefix.getComponentCount(); i++) {
|
||||
if (!qName.getComponents().get(i).equals(prefix.getComponents().get(i))) {
|
||||
return false;
|
||||
@Nullable
|
||||
private PyImportElement findMatchingImportElement(PyQualifiedName prefix) {
|
||||
final List<PyImportElement> imports = ((PyFileImpl)myContainingFile).getImportTargets();
|
||||
for (PyImportElement anImport : imports) {
|
||||
final PyQualifiedName qName = anImport.getImportedQName();
|
||||
if (qName != null && qName.matchesPrefix(prefix)) {
|
||||
return anImport;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean mustResolveOutside() {
|
||||
@@ -77,4 +82,22 @@ public class PyImportedModule extends LightElement implements NameDefiner {
|
||||
public String toString() {
|
||||
return "PyImportedModule:" + myImportedPrefix;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getNavigationElement() {
|
||||
final PyImportElement importElement = findMatchingImportElement(myImportedPrefix);
|
||||
if (importElement != null) {
|
||||
final PsiElement element = resolve(importElement, myImportedPrefix);
|
||||
if (element != null) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return super.getNavigationElement();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement resolve(PyImportElement importElement, final PyQualifiedName prefix) {
|
||||
return PyUtil.turnDirIntoInit(ResolveImportUtil.resolveImportElement(importElement, prefix));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.stubs.StubInputStream;
|
||||
import com.intellij.psi.stubs.StubOutputStream;
|
||||
import com.intellij.util.io.StringRef;
|
||||
@@ -62,6 +63,18 @@ public class PyQualifiedName {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean matchesPrefix(PyQualifiedName prefix) {
|
||||
if (getComponentCount() < prefix.getComponentCount()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < prefix.getComponentCount(); i++) {
|
||||
if (!getComponents().get(i).equals(prefix.getComponents().get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void serialize(@Nullable PyQualifiedName qName, StubOutputStream dataStream) throws IOException {
|
||||
if (qName == null) {
|
||||
dataStream.writeVarInt(0);
|
||||
@@ -99,11 +112,8 @@ public class PyQualifiedName {
|
||||
return myComponents.get(myComponents.size()-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Iterator<String> it = myComponents.iterator();
|
||||
if (it.hasNext()) sb.append(it.next());
|
||||
while(it.hasNext()) sb.append(".").append(it.next());
|
||||
return sb.toString();
|
||||
return StringUtil.join(myComponents, ".");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl {
|
||||
|
||||
@Override
|
||||
public boolean isReferenceTo(PsiElement element) {
|
||||
if (super.isReferenceTo(element)) {
|
||||
if (resolve() == element) {
|
||||
return true;
|
||||
}
|
||||
final String referencedName = myElement.getReferencedName();
|
||||
|
||||
@@ -241,6 +241,9 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
if (target instanceof PyFile) {
|
||||
return new PyModuleType((PyFile) target);
|
||||
}
|
||||
if (target instanceof PyImportedModule) {
|
||||
return new PyImportedModuleType((PyImportedModule) target);
|
||||
}
|
||||
if (target instanceof PyTargetExpression && context.allowDataFlow() && anchor != null) {
|
||||
final ScopeOwner scopeOwner = PsiTreeUtil.getParentOfType(anchor, ScopeOwner.class);
|
||||
if (scopeOwner != null && scopeOwner == PsiTreeUtil.getParentOfType(target, ScopeOwner.class)) {
|
||||
|
||||
@@ -68,6 +68,9 @@ public class ResolveImportUtil {
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiDirectory stepBackFrom(PsiFile base, int depth) {
|
||||
if (depth == 0) {
|
||||
return base.getContainingDirectory();
|
||||
}
|
||||
PsiDirectory result;
|
||||
if (base != null) {
|
||||
base = base.getOriginalFile(); // just to make sure
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.python.psi.PyImportElement;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import com.jetbrains.python.psi.impl.PyFileImpl;
|
||||
import com.jetbrains.python.psi.impl.PyImportedModule;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PyImportedModuleType implements PyType {
|
||||
private PyImportedModule myImportedModule;
|
||||
|
||||
public PyImportedModuleType(PyImportedModule importedModule) {
|
||||
myImportedModule = importedModule;
|
||||
}
|
||||
|
||||
public PsiElement resolveMember(String name) {
|
||||
return myImportedModule.getElementNamed(name);
|
||||
}
|
||||
|
||||
public Object[] getCompletionVariants(PyQualifiedExpression referenceExpression, ProcessingContext context) {
|
||||
List<LookupElement> result = new ArrayList<LookupElement>();
|
||||
final List<PyImportElement> importTargets = ((PyFileImpl)myImportedModule.getContainingFile()).getImportTargets();
|
||||
final int imported = myImportedModule.getImportedPrefix().getComponentCount();
|
||||
for (PyImportElement importTarget : importTargets) {
|
||||
final PyQualifiedName qName = importTarget.getImportedQName();
|
||||
if (qName != null && qName.matchesPrefix(myImportedModule.getImportedPrefix())) {
|
||||
final List<String> components = qName.getComponents();
|
||||
if (components.size() > imported) {
|
||||
String module = components.get(imported);
|
||||
result.add(LookupElementBuilder.create(module));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toArray(new Object[result.size()]);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "PyImportedModuleType:" + myImportedModule.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import root.nested_mod
|
||||
root.nested_mod
|
||||
@@ -0,0 +1,2 @@
|
||||
import root.nested_mod
|
||||
root.<caret>
|
||||
@@ -0,0 +1,3 @@
|
||||
class Spam(object):
|
||||
def eggs(self, parr<caret>ot):
|
||||
self.parrot = parrot
|
||||
@@ -28,4 +28,9 @@ public class PyFindUsagesTest extends PyLightFixtureTestCase {
|
||||
final Collection<UsageInfo> usages = myFixture.testFindUsages("findUsages/ImplicitlyResolvedUsages.py");
|
||||
assertEquals(1, usages.size());
|
||||
}
|
||||
|
||||
public void testQualifiedVsUnqualifiedUsages() { // PY-939
|
||||
final Collection<UsageInfo> usages = myFixture.testFindUsages("findUsages/QualifiedVsUnqualifiedUsages.py");
|
||||
assertEquals(1, usages.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,8 @@ public class PyMultiFileResolveTest extends PyLightFixtureTestCase {
|
||||
|
||||
public void testNestedPackageElement() throws Exception {
|
||||
PsiElement element = doResolve();
|
||||
assertTrue(element instanceof PyFile);
|
||||
element = element.getNavigationElement();
|
||||
assertInstanceOf(element, PyFile.class);
|
||||
assertEquals("__init__.py", ((PyFile) element).getName());
|
||||
}
|
||||
|
||||
|
||||
@@ -30,18 +30,29 @@ public class PyQuickFixTest extends PyLightFixtureTestCase {
|
||||
|
||||
public void testQualifyByImport() throws Exception {
|
||||
final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance();
|
||||
boolean oldValue = settings.PREFER_FROM_IMPORT;
|
||||
boolean oldPreferFrom = settings.PREFER_FROM_IMPORT;
|
||||
boolean oldHighlightUnused = settings.HIGHLIGHT_UNUSED_IMPORTS;
|
||||
settings.PREFER_FROM_IMPORT = false;
|
||||
settings.HIGHLIGHT_UNUSED_IMPORTS = false;
|
||||
try {
|
||||
doInspectionTest(new String[]{"QualifyByImport.py", "QualifyByImportFoo.py"}, PyUnresolvedReferencesInspection.class, PyBundle.message("ACT.qualify.with.module"), true, true);
|
||||
}
|
||||
finally {
|
||||
settings.PREFER_FROM_IMPORT = oldValue;
|
||||
settings.PREFER_FROM_IMPORT = oldPreferFrom;
|
||||
settings.HIGHLIGHT_UNUSED_IMPORTS = oldHighlightUnused;
|
||||
}
|
||||
}
|
||||
|
||||
public void testAddToImportFromList() throws Exception {
|
||||
doInspectionTest(new String[]{"AddToImportFromList.py", "AddToImportFromFoo.py"}, PyUnresolvedReferencesInspection.class, PyBundle.message("ACT.NAME.use.import"), true, true);
|
||||
final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance();
|
||||
boolean oldHighlightUnused = settings.HIGHLIGHT_UNUSED_IMPORTS;
|
||||
settings.HIGHLIGHT_UNUSED_IMPORTS = false;
|
||||
try {
|
||||
doInspectionTest(new String[]{"AddToImportFromList.py", "AddToImportFromFoo.py"}, PyUnresolvedReferencesInspection.class, PyBundle.message("ACT.NAME.use.import"), true, true);
|
||||
}
|
||||
finally {
|
||||
settings.HIGHLIGHT_UNUSED_IMPORTS = oldHighlightUnused;
|
||||
}
|
||||
}
|
||||
// TODO: add a test for multiple variants of above
|
||||
|
||||
|
||||
@@ -95,4 +95,13 @@ public class PythonCompletionTest extends PyLightFixtureTestCase {
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResultByFile(testName + ".after.py");
|
||||
}
|
||||
|
||||
public void testPy874() throws Exception {
|
||||
final String dirname = "completion/";
|
||||
final String testName = dirname + "py874";
|
||||
myFixture.configureByFile(testName + ".py");
|
||||
myFixture.copyDirectoryToProject(dirname + "root", dirname + "root");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResultByFile(testName + ".after.py");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user