Merging PyQualifiedName.toString()

This commit is contained in:
Dmitry Cheryasov
2010-05-05 17:55:44 +03:00
19 changed files with 160 additions and 33 deletions
@@ -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
+2
View File
@@ -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");
}
}