mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Closes PY-30, PY-37, PY-41, and a subtle import resolution bug introduced by the previous commit
which current test suite fails to detect.
Introduces a base class for list-comprehension-like classes, puts some life into generators.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
/**
|
||||
* The "for" part of list comprehensions and generators.
|
||||
* User: dcheryasov
|
||||
* Date: Jul 31, 2008
|
||||
*/
|
||||
public interface ComprhForComponent {
|
||||
PyExpression getIteratorVariable();
|
||||
PyExpression getIteratedList();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
/**
|
||||
* The "if" part of list comprehensions and generators.
|
||||
* User: dcheryasov
|
||||
* Date: Jul 31, 2008
|
||||
*/
|
||||
public interface ComprhIfComponent {
|
||||
PyExpression getTest();
|
||||
}
|
||||
@@ -50,6 +50,10 @@ public interface NameDefiner extends PsiElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper iterator-over-array class.
|
||||
* @param <T> array element type
|
||||
*/
|
||||
class ArrayIter<T> implements Iterator<T> {
|
||||
|
||||
protected int my_index;
|
||||
@@ -78,6 +82,10 @@ public interface NameDefiner extends PsiElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable that can only have one element.
|
||||
* @param <T> element type
|
||||
*/
|
||||
class SingleIterable<T> implements Iterable<T> {
|
||||
|
||||
T content;
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* Generator expression PSI.
|
||||
* User: yole
|
||||
* Date: 05.06.2005
|
||||
* Time: 10:15:46
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface PyGeneratorExpression extends PyExpression {
|
||||
public interface PyGeneratorExpression extends PyExpression, NameDefiner {
|
||||
PyExpression getResultExpression();
|
||||
List<ComprhForComponent> getForComponents();
|
||||
List<ComprhIfComponent> getIfComponents();
|
||||
}
|
||||
|
||||
@@ -19,25 +19,13 @@ package com.jetbrains.python.psi;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* List comprehension PSI.
|
||||
* User: yole
|
||||
* Date: 31.05.2005
|
||||
* Time: 23:32:57
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public interface PyListCompExpression extends PyExpression {
|
||||
PyExpression getResultExpression();
|
||||
List<ListCompComponent> getComponents();
|
||||
public interface PyListCompExpression extends PyExpression, NameDefiner {
|
||||
PyExpression getResultExpression();
|
||||
List<ComprhForComponent> getForComponents();
|
||||
List<ComprhIfComponent> getIfComponents();
|
||||
|
||||
interface ListCompComponent {
|
||||
}
|
||||
|
||||
interface IfComponent extends ListCompComponent {
|
||||
PyExpression getTest();
|
||||
}
|
||||
|
||||
interface ForComponent extends ListCompComponent {
|
||||
PyExpression getIteratorVariable();
|
||||
PyExpression getIteratedList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intellij.psi.TokenType;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
@@ -192,4 +193,45 @@ public class PyUtil {
|
||||
private static boolean isWhitespace(ASTNode node) {
|
||||
return node != null && node.getElementType().equals(TokenType.WHITE_SPACE);
|
||||
}
|
||||
|
||||
|
||||
protected static <T extends PyElement> List<T> _unfoldParenExprs(T[] targets, List<T> receiver) {
|
||||
// NOTE: this proliferation of instanceofs is not very beautiful. Maybe rewrite using a visitor.
|
||||
for (T exp : targets) {
|
||||
if (exp instanceof PyParenthesizedExpression) {
|
||||
final PyParenthesizedExpression parex = (PyParenthesizedExpression)exp;
|
||||
PyExpression cont = parex.getContainedExpression();
|
||||
if (cont instanceof PyTupleExpression) {
|
||||
final PyTupleExpression tupex = (PyTupleExpression)cont;
|
||||
_unfoldParenExprs((T[])tupex.getElements(), receiver);
|
||||
}
|
||||
else receiver.add(exp);
|
||||
}
|
||||
else receiver.add(exp);
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
|
||||
// Poor man's catamorhpism :)
|
||||
/**
|
||||
* Flattens the representation of every element in targets, and puts all results together.
|
||||
* Elements of every tuple nested in target item are brought to the top level: (a, (b, (c, d))) -> (a, b, c, d)
|
||||
* Typical usage: <code>flattenedParens(some_tuple.getExpressions())</code>.
|
||||
* @param targets target elements.
|
||||
* @return the list of flattened expressions.
|
||||
*/
|
||||
@NotNull
|
||||
public static <T extends PyElement> List<T> flattenedParens(T[] targets) {
|
||||
return _unfoldParenExprs(targets, new ArrayList<T>(targets.length));
|
||||
}
|
||||
|
||||
// Poor man's filter
|
||||
// TODO: move to a saner place
|
||||
public static boolean instanceOf(Object obj, Class... possibleClasses) {
|
||||
for (Class cls : possibleClasses) {
|
||||
if (cls.isInstance(obj)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,9 +27,6 @@ import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yole
|
||||
@@ -101,27 +98,11 @@ public class PyAssignmentStatementImpl extends PyElementImpl implements PyAssign
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static List<PyElement> _unfoldParenExprs(PyElement[] targets, List<PyElement> receiver) {
|
||||
// NOTE: this proliferation of instanceofs is not very beautiful. Maybe rewrite using a visitor.
|
||||
for (PyElement exp : targets) {
|
||||
if (exp instanceof PyParenthesizedExpression) {
|
||||
final PyParenthesizedExpression parex = (PyParenthesizedExpression)exp;
|
||||
PyExpression cont = parex.getContainedExpression();
|
||||
if (cont instanceof PyTupleExpression) {
|
||||
final PyTupleExpression tupex = (PyTupleExpression)cont;
|
||||
_unfoldParenExprs(tupex.getElements(), receiver);
|
||||
}
|
||||
else receiver.add(exp);
|
||||
}
|
||||
else receiver.add(exp);
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterable<PyElement> iterateNames() {
|
||||
PyExpression[] targets = getTargets();
|
||||
return _unfoldParenExprs(targets, new ArrayList<PyElement>(targets.length));
|
||||
PyElement[] targets = getTargets();
|
||||
// return _unfoldParenExprs(targets, new ArrayList<PyElement>(targets.length));
|
||||
return PyUtil.flattenedParens(targets);
|
||||
}
|
||||
|
||||
public PyElement getElementNamed(final String the_name) {
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Comprehension-like element base, for list comps ang generators.
|
||||
* User: dcheryasov
|
||||
* Date: Jul 31, 2008
|
||||
*/
|
||||
public class PyComprehensionElementImpl extends PyElementImpl implements NameDefiner {
|
||||
public PyComprehensionElementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* In "[x+1 for x in (1,2,3)]" result expression is "x+1".
|
||||
* @return result expression.
|
||||
*/
|
||||
public PyExpression getResultExpression() {
|
||||
ASTNode[] exprs = getNode().getChildren(PyElementTypes.EXPRESSIONS);
|
||||
return exprs.length == 0 ? null : (PyExpression)exprs[0].getPsi();
|
||||
}
|
||||
|
||||
/**
|
||||
* In "[x+1 for x in (1,2,3)]" a "for component" is "x".
|
||||
* @return all "for components"
|
||||
*/
|
||||
public List<ComprhForComponent> getForComponents() {
|
||||
ASTNode node = getNode().getFirstChildNode();
|
||||
List<ComprhForComponent> list = new ArrayList<ComprhForComponent>(5);
|
||||
while (node != null) {
|
||||
IElementType type = node.getElementType();
|
||||
ASTNode next = getNextExpression(node);
|
||||
if (next == null) break;
|
||||
if (type == PyTokenTypes.FOR_KEYWORD) {
|
||||
ASTNode next2 = getNextExpression(next);
|
||||
if (next2 == null) break;
|
||||
final PyExpression variable = (PyExpression)next.getPsi();
|
||||
final PyExpression iterated = (PyExpression)next2.getPsi();
|
||||
list.add(new ComprhForComponent() {
|
||||
public PyExpression getIteratorVariable() {
|
||||
return variable;
|
||||
}
|
||||
|
||||
public PyExpression getIteratedList() {
|
||||
return iterated;
|
||||
}
|
||||
});
|
||||
}
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<ComprhIfComponent> getIfComponents() {
|
||||
ASTNode node = getNode().getFirstChildNode();
|
||||
List<ComprhIfComponent> list = new ArrayList<ComprhIfComponent>(5);
|
||||
while (node != null) {
|
||||
IElementType type = node.getElementType();
|
||||
ASTNode next = getNextExpression(node);
|
||||
if (next == null) break;
|
||||
if (type == PyTokenTypes.IF_KEYWORD) {
|
||||
final PyExpression test = (PyExpression)next.getPsi();
|
||||
list.add(new ComprhIfComponent() {
|
||||
public PyExpression getTest() {
|
||||
return test;
|
||||
}
|
||||
});
|
||||
}
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static ASTNode getNextExpression(ASTNode after) {
|
||||
ASTNode node = after;
|
||||
do {
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
while (node != null && !PyElementTypes.EXPRESSIONS.contains(node.getElementType()));
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* In "[x+1 for x in (1,2,3) if x > 2]" an "if component" is "x > 2".
|
||||
* @return all "if components"
|
||||
*/
|
||||
@NotNull
|
||||
public Iterable<PyElement> iterateNames() {
|
||||
// extract whatever names are defined in "for" components
|
||||
List<ComprhForComponent> fors = getForComponents();
|
||||
PyElement[] for_targets = new PyElement[fors.size()];
|
||||
int i = 0;
|
||||
for (ComprhForComponent for_comp : fors) {
|
||||
for_targets[i] = for_comp.getIteratorVariable();
|
||||
i += 1;
|
||||
}
|
||||
List<PyElement> name_refs = PyUtil.flattenedParens(for_targets);
|
||||
return name_refs;
|
||||
}
|
||||
|
||||
public PsiElement getElementNamed(final String the_name) {
|
||||
return IterHelper.findName(iterateNames(), the_name);
|
||||
}
|
||||
|
||||
public boolean mustResolveOutside() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,12 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyGeneratorExpression;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
@@ -28,7 +31,7 @@ import com.jetbrains.python.psi.types.PyType;
|
||||
* Time: 10:16:07
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class PyGeneratorExpressionImpl extends PyElementImpl implements PyGeneratorExpression {
|
||||
public class PyGeneratorExpressionImpl extends PyComprehensionElementImpl implements PyGeneratorExpression {
|
||||
public PyGeneratorExpressionImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
@@ -41,4 +44,27 @@ public class PyGeneratorExpressionImpl extends PyElementImpl implements PyGenera
|
||||
public PyType getType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterable<PyElement> iterateNames() {
|
||||
// extract whatever names are defined in "for" components
|
||||
List<ComprhForComponent> fors = getForComponents();
|
||||
PyElement[] for_targets = new PyElement[fors.size()];
|
||||
int i = 0;
|
||||
for (ComprhForComponent for_comp : fors) {
|
||||
for_targets[i] = for_comp.getIteratorVariable();
|
||||
i += 1;
|
||||
}
|
||||
List<PyElement> name_refs = PyUtil.flattenedParens(for_targets);
|
||||
return name_refs;
|
||||
}
|
||||
|
||||
public PsiElement getElementNamed(final String the_name) {
|
||||
return IterHelper.findName(iterateNames(), the_name);
|
||||
}
|
||||
|
||||
public boolean mustResolveOutside() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,11 +29,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* The "import foo" or "import foo as bar" parts.
|
||||
* User: yole
|
||||
* Date: 02.06.2005
|
||||
* Time: 22:22:35
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class PyImportElementImpl extends PyElementImpl implements PyImportElement {
|
||||
public PyImportElementImpl(ASTNode astNode) {
|
||||
@@ -104,23 +102,11 @@ public class PyImportElementImpl extends PyElementImpl implements PyImportElemen
|
||||
public PsiElement getElementNamed(final String the_name) {
|
||||
PyElement named_elt = IterHelper.findName(iterateNames(), the_name);
|
||||
if (named_elt != null) {
|
||||
PsiElement from_elt = null;
|
||||
PyReferenceExpression import_ref = getImportReference(); // import what?
|
||||
if (import_ref == null) return null;
|
||||
String import_ref_name = import_ref.getName();
|
||||
if (import_ref_name == null) return null; // no imported name
|
||||
/*
|
||||
PyFromImportStatement import_from_stmt = PsiTreeUtil.getParentOfType(this, PyFromImportStatement.class);
|
||||
if (import_from_stmt != null) {
|
||||
PyReferenceExpression from_src = import_from_stmt.getImportSource();
|
||||
if (from_src != null) {
|
||||
//return ResolveImportUtil.resolvePythonImport2(from_src, import_ref_name);
|
||||
return ResolveImportUtil.resolveImportReference(import_ref);
|
||||
}
|
||||
PyReferenceExpression import_ref = getImportReference(); // = most qualified import name: "z" for "import x.y.z"
|
||||
if (getAsName() == null) { // the match was not by target expr of "import ... as foo"
|
||||
if (named_elt instanceof PyReferenceExpression) import_ref = (PyReferenceExpression)named_elt; // [part of] import ref matched
|
||||
else return null; // I wonder what could have matched there?
|
||||
}
|
||||
// else return ResolveImportUtil.resolvePythonImport2(import_ref, null);
|
||||
else return ResolveImportUtil.resolveImportReference(import_ref);
|
||||
*/
|
||||
return ResolveImportUtil.resolveImportReference(import_ref);
|
||||
}
|
||||
// no element of this name
|
||||
|
||||
@@ -20,18 +20,11 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.PsiCached;
|
||||
import com.jetbrains.python.psi.ComprhForComponent;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyListCompExpression;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
@@ -40,7 +33,7 @@ import java.util.List;
|
||||
* Time: 23:33:16
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class PyListCompExpressionImpl extends PyElementImpl implements PyListCompExpression {
|
||||
public class PyListCompExpressionImpl extends PyComprehensionElementImpl implements PyListCompExpression {
|
||||
public PyListCompExpressionImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
@@ -50,68 +43,16 @@ public class PyListCompExpressionImpl extends PyElementImpl implements PyListCom
|
||||
pyVisitor.visitPyListCompExpression(this);
|
||||
}
|
||||
|
||||
@PsiCached
|
||||
public PyExpression getResultExpression() {
|
||||
ASTNode[] exprs = getNode().getChildren(PyElementTypes.EXPRESSIONS);
|
||||
return exprs.length == 0 ? null : (PyExpression)exprs[0].getPsi();
|
||||
}
|
||||
|
||||
@PsiCached
|
||||
public List<ListCompComponent> getComponents() {
|
||||
ASTNode node = getNode().getFirstChildNode();
|
||||
List<ListCompComponent> list = new ArrayList<ListCompComponent>(5);
|
||||
while (node != null) {
|
||||
IElementType type = node.getElementType();
|
||||
ASTNode next = getNextExpression(node);
|
||||
if (next == null) break;
|
||||
if (type == PyTokenTypes.IF_KEYWORD) {
|
||||
final PyExpression test = (PyExpression)next.getPsi();
|
||||
list.add(new IfComponent() {
|
||||
public PyExpression getTest() {
|
||||
return test;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (type == PyTokenTypes.FOR_KEYWORD) {
|
||||
ASTNode next2 = getNextExpression(next);
|
||||
if (next2 == null) break;
|
||||
final PyExpression variable = (PyExpression)next.getPsi();
|
||||
final PyExpression iterated = (PyExpression)next2.getPsi();
|
||||
list.add(new ForComponent() {
|
||||
public PyExpression getIteratorVariable() {
|
||||
return variable;
|
||||
}
|
||||
|
||||
public PyExpression getIteratedList() {
|
||||
return iterated;
|
||||
}
|
||||
});
|
||||
}
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static ASTNode getNextExpression(ASTNode after) {
|
||||
ASTNode node = after;
|
||||
do {
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
while (node != null && !PyElementTypes.EXPRESSIONS.contains(node.getElementType()));
|
||||
return node;
|
||||
}
|
||||
|
||||
public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
|
||||
@NotNull ResolveState substitutor,
|
||||
PsiElement lastParent,
|
||||
@NotNull PsiElement place) {
|
||||
for (ListCompComponent component : getComponents()) {
|
||||
if (component instanceof ForComponent) {
|
||||
for (ComprhForComponent component : getForComponents()) {
|
||||
if (component != null) {
|
||||
//TODO: this needs to restrict resolution based on nesting
|
||||
// for example, this is not valid (the i in the first for should not resolve):
|
||||
// x for x in i for i in y
|
||||
ForComponent forComponent = (ForComponent)component;
|
||||
if (!forComponent.getIteratorVariable().processDeclarations(processor, substitutor, null, place)) return false;
|
||||
if (!component.getIteratorVariable().processDeclarations(processor, substitutor, null, place)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -120,4 +61,5 @@ public class PyListCompExpressionImpl extends PyElementImpl implements PyListCom
|
||||
public PyType getType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -144,8 +144,14 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
|
||||
// here we have an unqualified expr. it may be defined:
|
||||
// ...in current file
|
||||
//PsiElement ret = PyResolveUtil.treeWalkUp(new PyResolveUtil.ResolveProcessor(referencedName), this, this, null);
|
||||
PsiElement ret = PyResolveUtil.treeCrawlUp(new PyResolveUtil.ResolveProcessor(referencedName), this);
|
||||
if ((ret != null) && (ret instanceof PyClass)) {
|
||||
// is it a case of the bizarre "class Foo(Foo)" construct?
|
||||
PyClass cls = (PyClass)ret;
|
||||
for (PyExpression base_expr : cls.getSuperClassExpressions()){
|
||||
if (base_expr == this) return null; // cannot resolve us, the base class ref, to the class being defined
|
||||
}
|
||||
}
|
||||
if (ret == null) {
|
||||
// ...as a part of current module
|
||||
PyType otype = PyBuiltinCache.getInstance(this.getProject()).getObjectType(); // "object" as a closest kin to "module"
|
||||
|
||||
@@ -12,20 +12,13 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.FilenameIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyFromImportStatement;
|
||||
import com.jetbrains.python.psi.PyImportStatement;
|
||||
import com.jetbrains.python.psi.PyReferenceExpression;
|
||||
import com.jetbrains.python.psi.types.PyModuleType;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -64,7 +57,7 @@ public class AddImportAction implements HintAction, QuestionAction {
|
||||
final PsiElement element = myReference.getElement();
|
||||
if (myReference instanceof PyReferenceExpression) {
|
||||
final PyExpression qual = ((PyReferenceExpression)myReference).getQualifier();
|
||||
if ((qual != null) && (qual.getType() instanceof PyModuleType)) return false; // don't propose to import unknown fields, etc
|
||||
if ((qual != null) /*&& (qual.getType() instanceof PyModuleType)*/) return false; // don't propose to import unknown fields, etc
|
||||
}
|
||||
if (PsiTreeUtil.getParentOfType(element, PyImportStatement.class) != null) return false;
|
||||
if (PsiTreeUtil.getParentOfType(element, PyFromImportStatement.class) != null) return false;
|
||||
@@ -83,9 +76,11 @@ public class AddImportAction implements HintAction, QuestionAction {
|
||||
final String referenceName = getRefName();
|
||||
final PsiFile[] files = getRefFiles(referenceName);
|
||||
if (files.length == 1) {
|
||||
final PyImportStatement importNodeToInsert = PythonLanguage.getInstance().getElementGenerator().createImportStatementFromText(myProject, "import " + referenceName);
|
||||
final PyImportStatement importNodeToInsert = PythonLanguage.getInstance().getElementGenerator().createImportStatementFromText(
|
||||
myProject, "import " + referenceName + "\n\n"
|
||||
);
|
||||
try {
|
||||
file.addBefore(importNodeToInsert, getFirstNonComment(file));
|
||||
file.addAfter(importNodeToInsert, getInsertPosition(file));
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
@@ -95,11 +90,20 @@ public class AddImportAction implements HintAction, QuestionAction {
|
||||
});
|
||||
}
|
||||
|
||||
private static PsiElement getFirstNonComment(final PsiFile file) {
|
||||
final PsiElement firstChild = file.getFirstChild();
|
||||
LOG.assertTrue(firstChild != null);
|
||||
final PsiElement element = PsiTreeUtil.skipSiblingsForward(firstChild, PsiComment.class);
|
||||
return element != null ? element : firstChild;
|
||||
private static PsiElement getInsertPosition(final PsiFile file) {
|
||||
PsiElement feeler = file.getFirstChild();
|
||||
LOG.assertTrue(feeler != null);
|
||||
// skip initial comments and whitespace and try to get just below the last import stmt
|
||||
PsiElement seeker = feeler;
|
||||
do {
|
||||
if (PyUtil.instanceOf(feeler, PyImportStatement.class, PyFromImportStatement.class)) {
|
||||
seeker = feeler;
|
||||
feeler = feeler.getNextSibling();
|
||||
}
|
||||
else if (PyUtil.instanceOf(feeler, PsiWhiteSpace.class, PsiComment.class)) feeler = feeler.getNextSibling();
|
||||
else break; // some other statement, stop
|
||||
} while (feeler != null);
|
||||
return seeker;
|
||||
}
|
||||
|
||||
public boolean startInWriteAction() {
|
||||
|
||||
@@ -21,11 +21,9 @@ import com.jetbrains.python.psi.PyParameter;
|
||||
import com.jetbrains.python.psi.PyParameterList;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* Checks for anomalies in parameter lists of function declarations.
|
||||
* User: yole
|
||||
* Date: 12.06.2005
|
||||
* Time: 11:05:22
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class ParameterListAnnotator extends PyAnnotator {
|
||||
@Override public void visitPyParameterList(final PyParameterList node) {
|
||||
|
||||
Reference in New Issue
Block a user