{
@Nullable
- PyReferenceExpression getImportReference();
+ PyReferenceExpression getImportReferenceExpression();
@Nullable
PyQualifiedName getImportedQName();
diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java
index fd6870d6db19..322104574905 100644
--- a/python/src/com/jetbrains/python/psi/PyUtil.java
+++ b/python/src/com/jetbrains/python/psi/PyUtil.java
@@ -17,13 +17,11 @@ import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
-import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.awt.RelativePoint;
@@ -39,9 +37,6 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType;
import com.jetbrains.python.documentation.EpydocUtil;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
-import com.jetbrains.python.psi.impl.PyQualifiedName;
-import com.jetbrains.python.psi.stubs.PyFunctionStub;
-import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyTupleType;
import com.jetbrains.python.psi.types.PyType;
@@ -58,9 +53,8 @@ import java.io.IOException;
import java.util.*;
import java.util.List;
-import static com.jetbrains.python.psi.PyFunction.Flag.CLASSMETHOD;
-import static com.jetbrains.python.psi.PyFunction.Flag.STATICMETHOD;
-import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.interpretAsStaticmethodOrClassmethodWrappingCall;
+import static com.jetbrains.python.psi.PyFunction.Modifier.CLASSMETHOD;
+import static com.jetbrains.python.psi.PyFunction.Modifier.STATICMETHOD;
public class PyUtil {
private PyUtil() {
@@ -443,42 +437,6 @@ public class PyUtil {
if (!thing) throw new IncorrectOperationException();
}
- /**
- * When a function is decorated many decorators, finds the deepest builtin decorator:
- *
- * @foo
- * @classmethod # <-- that's it
- * @bar
- * def moo(cls):
- * pass
- *
- * @param node the allegedly decorated function
- * @return name of the built-in decorator, or null (even if there are non-built-in decorators).
- */
- @Nullable
- public static String getClassOrStaticMethodDecorator(@NotNull final PyFunction node) {
- PyDecoratorList decolist = node.getDecoratorList();
- if (decolist != null) {
- PyDecorator[] decos = decolist.getDecorators();
- if (decos.length > 0) {
- for (int i = decos.length - 1; i >= 0; i -= 1) {
- PyDecorator deco = decos[i];
- String deconame = deco.getName();
- if (PyNames.CLASSMETHOD.equals(deconame) || PyNames.STATICMETHOD.equals(deconame)) {
- return deconame;
- }
- for(PyKnownDecoratorProvider provider: KnownDecoratorProviderHolder.KNOWN_DECORATOR_PROVIDERS) {
- String name = provider.toKnownDecorator(deconame);
- if (name != null) {
- return name;
- }
- }
- }
- }
- }
- return null;
- }
-
public static boolean isInstanceAttribute(PyExpression target) {
if (!(target instanceof PyTargetExpression)) {
return false;
@@ -612,80 +570,6 @@ public class PyUtil {
}
}
- /**
- * Looks for two standard decorators to a function, or a wrapping assignment that closely follows it.
- *
- * @param function what to analyze
- * @return a set of flags describing what was detected.
- */
- @NotNull
- public static Set detectDecorationsAndWrappersOf(PyFunction function) {
- Set flags = EnumSet.noneOf(PyFunction.Flag.class);
- String deconame = getClassOrStaticMethodDecorator(function);
- if (PyNames.CLASSMETHOD.equals(deconame)) {
- flags.add(CLASSMETHOD);
- }
- else if (PyNames.STATICMETHOD.equals(deconame)) flags.add(STATICMETHOD);
- // implicit staticmethod __new__
- PyClass cls = function.getContainingClass();
- if (cls != null && PyNames.NEW.equals(function.getName()) && cls.isNewStyleClass()) flags.add(STATICMETHOD);
- //
- if (!flags.contains(CLASSMETHOD) && !flags.contains(STATICMETHOD)) { // not set by decos, look for reassignment
- final PyFunctionStub stub = function.getStub();
- if (stub != null) {
- return getWrappersFromStub(stub);
- }
- String func_name = function.getName();
- if (func_name != null) {
- PyAssignmentStatement assignment = PsiTreeUtil.getNextSiblingOfType(function, PyAssignmentStatement.class);
- if (assignment != null) {
- for (Pair pair : assignment.getTargetsToValuesMapping()) {
- PyExpression value = pair.getSecond();
- if (value instanceof PyCallExpression) {
- PyExpression target = pair.getFirst();
- if (target instanceof PyTargetExpression && func_name.equals(target.getName())) {
- Pair interpreted = interpretAsStaticmethodOrClassmethodWrappingCall((PyCallExpression)value, function);
- if (interpreted != null) {
- PyFunction original = interpreted.getSecond();
- if (original == function) {
- String wrapper_name = interpreted.getFirst();
- if (PyNames.CLASSMETHOD.equals(wrapper_name)) {
- flags.add(CLASSMETHOD);
- }
- else if (PyNames.STATICMETHOD.equals(wrapper_name)) flags.add(STATICMETHOD);
- }
- }
- }
- }
- }
- }
- }
- }
- return flags;
- }
-
- private static Set getWrappersFromStub(PyFunctionStub stub) {
- final StubElement parentStub = stub.getParentStub();
- final List childrenStubs = parentStub.getChildrenStubs();
- int index = childrenStubs.indexOf(stub);
- if (index >= 0 && index < childrenStubs.size() - 1) {
- StubElement nextStub = (StubElement) childrenStubs.get(index+1);
- if (nextStub instanceof PyTargetExpressionStub) {
- final PyTargetExpressionStub targetExpressionStub = (PyTargetExpressionStub)nextStub;
- if (targetExpressionStub.getInitializerType() == PyTargetExpressionStub.InitializerType.CallExpression) {
- final PyQualifiedName qualifiedName = targetExpressionStub.getInitializer();
- if (PyQualifiedName.fromComponents(PyNames.CLASSMETHOD).equals(qualifiedName)) {
- return EnumSet.of(PyFunction.Flag.CLASSMETHOD);
- }
- if (PyQualifiedName.fromComponents(PyNames.STATICMETHOD).equals(qualifiedName)) {
- return EnumSet.of(PyFunction.Flag.STATICMETHOD);
- }
- }
- }
- }
- return EnumSet.noneOf(PyFunction.Flag.class);
- }
-
/**
* Returns child element in the psi tree
*
@@ -999,7 +883,7 @@ public class PyUtil {
public static MethodFlags of(@NotNull PyFunction node) {
PyClass cls = node.getContainingClass();
if (cls != null) {
- Set flags = detectDecorationsAndWrappersOf(node);
+ PyFunction.Modifier modifier = node.getModifier();
boolean isMetaclassMethod = false;
PyClass type_cls = PyBuiltinCache.getInstance(node).getClass("type");
for (PyClass ancestor_cls : cls.iterateAncestorClasses()) {
@@ -1010,7 +894,7 @@ public class PyUtil {
}
final String method_name = node.getName();
boolean isSpecialMetaclassMethod = isMetaclassMethod && method_name != null && among(method_name, PyNames.INIT, "__call__");
- return new MethodFlags(flags.contains(CLASSMETHOD), flags.contains(STATICMETHOD), isMetaclassMethod, isSpecialMetaclassMethod);
+ return new MethodFlags(modifier == CLASSMETHOD, modifier == STATICMETHOD, isMetaclassMethod, isSpecialMetaclassMethod);
}
return null;
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
index 0d8e6e51c88d..c33a5de1aaeb 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
@@ -139,7 +139,7 @@ public class PyCallExpressionHelper {
@Nullable
public static PyCallExpression.PyMarkedCallee resolveCallee(PyCallExpression us, PyResolveContext resolveContext, int implicitOffset) {
- PyFunction.Flag wrappedFlag = null;
+ PyFunction.Modifier wrappedModifier = null;
boolean isConstructorCall = false;
PyExpression callee = us.getCallee();
@@ -167,17 +167,17 @@ public class PyCallExpressionHelper {
resolved = wrapperInfo.getSecond();
String wrapper_name = wrapperInfo.getFirst();
if (PyNames.CLASSMETHOD.equals(wrapper_name)) {
- wrappedFlag = PyFunction.Flag.CLASSMETHOD;
+ wrappedModifier = PyFunction.Modifier.CLASSMETHOD;
}
- else if (PyNames.STATICMETHOD.equals(wrapper_name)) wrappedFlag = PyFunction.Flag.STATICMETHOD;
+ else if (PyNames.STATICMETHOD.equals(wrapper_name)) wrappedModifier = PyFunction.Modifier.STATICMETHOD;
}
}
if (resolved instanceof Callable) {
- Set flags = resolved instanceof PyFunction
- ? PyUtil.detectDecorationsAndWrappersOf((PyFunction) resolved)
- : EnumSet.noneOf(PyFunction.Flag.class);
- if (wrappedFlag != null) {
- flags.add(wrappedFlag);
+ PyFunction.Modifier modifier = resolved instanceof PyFunction
+ ? ((PyFunction)resolved).getModifier()
+ : null;
+ if (modifier == null && wrappedModifier != null) {
+ modifier = wrappedModifier;
}
List qualifiers = resolveResult != null ? resolveResult.getQualifiers() : Collections.emptyList();
boolean isByInstance = isConstructorCall ||
@@ -187,16 +187,16 @@ public class PyCallExpressionHelper {
boolean isByClass = lastQualifier == null ? false : isQualifiedByClass((Callable)resolved, lastQualifier, resolveContext.getTypeEvalContext());
final Callable callable = (Callable)resolved;
- implicitOffset += getImplicitArgumentCount(callable, flags, isConstructorCall, isByInstance, isByClass);
+ implicitOffset += getImplicitArgumentCount(callable, modifier, isConstructorCall, isByInstance, isByClass);
implicitOffset = implicitOffset < 0? 0: implicitOffset; // wrong source can trigger strange behaviour
- return new PyCallExpression.PyMarkedCallee(callable, flags, implicitOffset,
+ return new PyCallExpression.PyMarkedCallee(callable, modifier, implicitOffset,
resolveResult != null ? resolveResult.isImplicit() : false);
}
return null;
}
/**
- * Calls the {@link #getImplicitArgumentCount(PyExpression, Callable, PyFunction.Flag, EnumSet, boolean) full version}
+ * Calls the {@link #getImplicitArgumentCount(PyExpression, Callable, com.jetbrains.python.psi.PyFunction.Modifier, EnumSet< com.jetbrains.python.psi.PyFunction.Modifier >, boolean) full version}
* with null flags and with isByInstance inferred directly from call site (won't work with reassigned bound methods).
*
* @param callReference the call site, where arguments are given.
@@ -215,7 +215,7 @@ public class PyCallExpressionHelper {
QualifiedResolveResult followed = callReference.followAssignmentsChain(resolveContext);
boolean isByInstance = isQualifiedByInstance(functionBeingCalled, followed.getQualifiers(), resolveContext.getTypeEvalContext());
boolean isByClass = isQualifiedByInstance(functionBeingCalled, followed.getQualifiers(), resolveContext.getTypeEvalContext());
- return getImplicitArgumentCount(functionBeingCalled, PyUtil.detectDecorationsAndWrappersOf(functionBeingCalled), false, isByInstance, isByClass);
+ return getImplicitArgumentCount(functionBeingCalled, functionBeingCalled.getModifier(), false, isByInstance, isByClass);
}
/**
@@ -229,7 +229,7 @@ public class PyCallExpressionHelper {
*/
private static int getImplicitArgumentCount(
Callable callable,
- Set flags,
+ PyFunction.Modifier modifier,
boolean isConstructorCall,
boolean isByInstance,
boolean isByClass
@@ -247,10 +247,10 @@ public class PyCallExpressionHelper {
}
// decorators?
- if (flags.contains(PyFunction.Flag.STATICMETHOD)) {
+ if (modifier == PyFunction.Modifier.STATICMETHOD) {
if (isByInstance && implicit_offset > 0) implicit_offset -= 1; // might have marked it as implicit 'self'
}
- else if (flags.contains(PyFunction.Flag.CLASSMETHOD)) {
+ else if (modifier == PyFunction.Modifier.CLASSMETHOD) {
if (!isByInstance) implicit_offset += 1; // Both Foo.method() and foo.method() have implicit the first arg
}
return implicit_offset;
diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
index d123a6a0486f..fe444fc6b4af 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
@@ -119,7 +119,7 @@ public class PyDecoratorImpl extends PyPresentableElementImpl i
if (callee == null) return null;
if (!hasArgumentList()) {
// NOTE: that +1 thing looks fishy
- callee = new PyMarkedCallee(callee.getCallable(), callee.getFlags(), callee.getImplicitOffset() + 1, callee.isImplicitlyResolved());
+ callee = new PyMarkedCallee(callee.getCallable(), callee.getModifier(), callee.getImplicitOffset() + 1, callee.isImplicitlyResolved());
}
return callee;
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
index ccf5a72267b1..fa0452ee37c6 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
@@ -2,6 +2,7 @@ package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
@@ -25,6 +26,7 @@ import com.jetbrains.python.documentation.StructuredDocString;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
+import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
@@ -33,6 +35,10 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
+import static com.jetbrains.python.psi.PyFunction.Modifier.CLASSMETHOD;
+import static com.jetbrains.python.psi.PyFunction.Modifier.STATICMETHOD;
+import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.interpretAsStaticmethodOrClassmethodWrappingCall;
+
/**
* Implements PyFunction.
*/
@@ -416,4 +422,115 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp
}
return super.getUseScope();
}
+
+ /**
+ * Looks for two standard decorators to a function, or a wrapping assignment that closely follows it.
+ *
+ * @return a flag describing what was detected.
+ */
+ @Nullable
+ public Modifier getModifier() {
+ String deconame = getClassOrStaticMethodDecorator();
+ if (PyNames.CLASSMETHOD.equals(deconame)) {
+ return CLASSMETHOD;
+ }
+ else if (PyNames.STATICMETHOD.equals(deconame)) {
+ return STATICMETHOD;
+ }
+ // implicit staticmethod __new__
+ PyClass cls = getContainingClass();
+ if (cls != null && PyNames.NEW.equals(getName()) && cls.isNewStyleClass()) {
+ return STATICMETHOD;
+ }
+ //
+ if (getStub() != null) {
+ return getWrappersFromStub();
+ }
+ String func_name = getName();
+ if (func_name != null) {
+ PyAssignmentStatement assignment = PsiTreeUtil.getNextSiblingOfType(this, PyAssignmentStatement.class);
+ if (assignment != null) {
+ for (Pair pair : assignment.getTargetsToValuesMapping()) {
+ PyExpression value = pair.getSecond();
+ if (value instanceof PyCallExpression) {
+ PyExpression target = pair.getFirst();
+ if (target instanceof PyTargetExpression && func_name.equals(target.getName())) {
+ Pair interpreted = interpretAsStaticmethodOrClassmethodWrappingCall((PyCallExpression)value, this);
+ if (interpreted != null) {
+ PyFunction original = interpreted.getSecond();
+ if (original == this) {
+ String wrapper_name = interpreted.getFirst();
+ if (PyNames.CLASSMETHOD.equals(wrapper_name)) {
+ return CLASSMETHOD;
+ }
+ else if (PyNames.STATICMETHOD.equals(wrapper_name)) {
+ return STATICMETHOD;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private Modifier getWrappersFromStub() {
+ final StubElement parentStub = getStub().getParentStub();
+ final List childrenStubs = parentStub.getChildrenStubs();
+ int index = childrenStubs.indexOf(getStub());
+ if (index >= 0 && index < childrenStubs.size() - 1) {
+ StubElement nextStub = (StubElement) childrenStubs.get(index+1);
+ if (nextStub instanceof PyTargetExpressionStub) {
+ final PyTargetExpressionStub targetExpressionStub = (PyTargetExpressionStub)nextStub;
+ if (targetExpressionStub.getInitializerType() == PyTargetExpressionStub.InitializerType.CallExpression) {
+ final PyQualifiedName qualifiedName = targetExpressionStub.getInitializer();
+ if (PyQualifiedName.fromComponents(PyNames.CLASSMETHOD).equals(qualifiedName)) {
+ return Modifier.CLASSMETHOD;
+ }
+ if (PyQualifiedName.fromComponents(PyNames.STATICMETHOD).equals(qualifiedName)) {
+ return Modifier.STATICMETHOD;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * When a function is decorated many decorators, finds the deepest builtin decorator:
+ *
+ * @foo
+ * @classmethod # <-- that's it
+ * @bar
+ * def moo(cls):
+ * pass
+ *
+ * @return name of the built-in decorator, or null (even if there are non-built-in decorators).
+ */
+ @Nullable
+ private String getClassOrStaticMethodDecorator() {
+ PyDecoratorList decolist = getDecoratorList();
+ if (decolist != null) {
+ PyDecorator[] decos = decolist.getDecorators();
+ if (decos.length > 0) {
+ for (int i = decos.length - 1; i >= 0; i -= 1) {
+ PyDecorator deco = decos[i];
+ String deconame = deco.getName();
+ if (PyNames.CLASSMETHOD.equals(deconame) || PyNames.STATICMETHOD.equals(deconame)) {
+ return deconame;
+ }
+ for(PyKnownDecoratorProvider provider: PyUtil.KnownDecoratorProviderHolder.KNOWN_DECORATOR_PROVIDERS) {
+ String name = provider.toKnownDecorator(deconame);
+ if (name != null) {
+ return name;
+ }
+ }
+ }
+ }
+ }
+ 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 4973c5469e47..cdb3760c52e7 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java
@@ -42,7 +42,7 @@ public class PyImportElementImpl extends PyBaseElementImpl
}
@Nullable
- public PyReferenceExpression getImportReference() {
+ public PyReferenceExpression getImportReferenceExpression() {
final ASTNode node = getNode().findChildByType(PyElementTypes.REFERENCE_EXPRESSION);
return node == null ? null : (PyReferenceExpression) node.getPsi();
}
@@ -52,7 +52,7 @@ public class PyImportElementImpl extends PyBaseElementImpl
if (stub != null) {
return stub.getImportedQName();
}
- final PyReferenceExpression importReference = getImportReference();
+ final PyReferenceExpression importReference = getImportReferenceExpression();
return importReference != null ? importReference.asQualifiedName() : null;
}
@@ -120,7 +120,7 @@ public class PyImportElementImpl extends PyBaseElementImpl
if (place.getContainingFile() != getContainingFile()) {
return true;
}
- final PyReferenceExpression importRef = getImportReference();
+ final PyReferenceExpression importRef = getImportReferenceExpression();
if (importRef != null) {
final PsiElement element = importRef.getReference().resolve();
if (element != null) {
@@ -136,7 +136,7 @@ public class PyImportElementImpl extends PyBaseElementImpl
@NotNull
private String getRefName(String default_name) {
- PyReferenceExpression ref = getImportReference();
+ PyReferenceExpression ref = getImportReferenceExpression();
if (ref != null) {
String refname = ref.getName();
if (refname != null) return refname;
@@ -156,7 +156,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(PyResolveUtil.toPath(imp_src));
}
else {
buf.append(">");
@@ -189,7 +189,7 @@ public class PyImportElementImpl extends PyBaseElementImpl
public Iterable iterateNames() {
PyElement ret = getAsNameElement();
if (ret == null) {
- List unwound_path = PyResolveUtil.unwindQualifiers(getImportReference());
+ List unwound_path = PyResolveUtil.unwindQualifiers(getImportReferenceExpression());
if ((unwound_path != null) && (unwound_path.size() > 0)) ret = unwound_path.get(0);
}
if (ret == null) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportReference.java
similarity index 87%
rename from python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java
rename to python/src/com/jetbrains/python/psi/impl/PyImportReference.java
index 63d79ee80359..8393d095c98c 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyImportReference.java
@@ -29,14 +29,24 @@ import java.util.*;
/**
* @author yole
*/
-public class PyImportReferenceImpl extends PyReferenceImpl {
+public class PyImportReference extends PyReferenceImpl {
private final PyReferenceExpressionImpl myElement;
- public PyImportReferenceImpl(PyReferenceExpressionImpl element, PyResolveContext context) {
+ public PyImportReference(PyReferenceExpressionImpl element, PyResolveContext context) {
super(element, context);
myElement = element;
}
+
+ @Override
+ public String getUnresolvedDescription() {
+ final PyImportStatement importStatement = PsiTreeUtil.getParentOfType(myElement, PyImportStatement.class);
+ if (importStatement != null) {
+ return "No module named " + myElement.getReferencedName();
+ }
+ return super.getUnresolvedDescription();
+ }
+
@NotNull
@Override
protected List resolveInner() {
@@ -44,21 +54,37 @@ public class PyImportReferenceImpl extends PyReferenceImpl {
final String referencedName = myElement.getReferencedName();
if (referencedName == null) return ret;
- int default_submodule_rate = RatedResolveResult.RATE_HIGH;
+ int defaultSubmoduleRate = RatedResolveResult.RATE_HIGH;
// names inside module take precedence over submodules
final PyImportElement import_elt = PsiTreeUtil.getParentOfType(myElement, PyImportElement.class);
if (import_elt != null) {
if (ret.poke(ResolveImportUtil.findImportedNameInsideModule(import_elt, referencedName), RatedResolveResult.RATE_HIGH)) {
- default_submodule_rate = RatedResolveResult.RATE_NORMAL;
+ defaultSubmoduleRate = RatedResolveResult.RATE_NORMAL;
}
}
- List targets = ResolveImportUtil.resolveImportReference(myElement);
+ final PyElement parent = PsiTreeUtil.getParentOfType(myElement, PyImportElement.class, PyFromImportStatement.class); //importRef.getParent();
+ List targets;
+ final PyQualifiedName qname = myElement.asQualifiedName();
+ if (parent instanceof PyImportElement) {
+ targets = ResolveImportUtil.multiResolveImportElement((PyImportElement)parent, qname);
+ }
+ else if (parent instanceof PyFromImportStatement) { // "from foo import"
+ targets = ResolveImportUtil.resolveFromOrForeignImport((PyFromImportStatement)parent, qname);
+ }
+ else {
+ return ret;
+ }
+ addRatedResults(ret, defaultSubmoduleRate, targets);
+ return ret;
+ }
+
+ private static void addRatedResults(ResolveResultList ret, int defaultSubmoduleRate, List targets) {
for (PsiElement target : targets) {
target = PyUtil.turnDirIntoInit(target);
if (target != null) { // ignore dirs without __init__.py, worthless
- int rate = default_submodule_rate;
+ int rate = defaultSubmoduleRate;
if (target instanceof PyFile) {
VirtualFile vFile = ((PyFile)target).getVirtualFile();
if (vFile != null && vFile.getLength() == 0) {
@@ -68,8 +94,6 @@ public class PyImportReferenceImpl extends PyReferenceImpl {
ret.poke(target, rate);
}
}
-
- return ret;
}
@NotNull
@@ -250,17 +274,15 @@ public class PyImportReferenceImpl extends PyReferenceImpl {
}
private void fillFromQName(PyQualifiedName thisQName, InsertHandler insertHandler) {
- final List dirs = ResolveImportUtil.resolveModulesInRoots(thisQName, myCurrentFile);
- for (PsiElement dir : dirs) {
- if (dir instanceof PsiDirectory) {
- fillFromDir((PsiDirectory)dir, insertHandler);
- }
+ QualifiedNameResolver visitor = new QualifiedNameResolver(thisQName).fromElement(myCurrentFile);
+ for (PsiDirectory dir : visitor.resultsOfType(PsiDirectory.class)) {
+ fillFromDir(dir, insertHandler);
}
}
private void addImportedNames(@NotNull PyImportElement[] import_elts) {
for (PyImportElement ielt : import_elts) {
- PyReferenceExpression ref = ielt.getImportReference();
+ PyReferenceExpression ref = ielt.getImportReferenceExpression();
if (ref != null) {
String s = ref.getReferencedName();
if (s != null) myNamesAlready.add(s);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportStatementNavigator.java b/python/src/com/jetbrains/python/psi/impl/PyImportStatementNavigator.java
index e6a3fd01ba4a..352c6d960b72 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyImportStatementNavigator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyImportStatementNavigator.java
@@ -3,7 +3,6 @@ package com.jetbrains.python.psi.impl;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.PyImportElement;
-import com.jetbrains.python.psi.PyImportStatement;
import com.jetbrains.python.psi.PyImportStatementBase;
import org.jetbrains.annotations.Nullable;
@@ -21,7 +20,7 @@ public class PyImportStatementNavigator {
return null;
}
for (PyImportElement importElement : statement.getImportElements()) {
- if (element == importElement || element == importElement.getImportReference()){
+ if (element == importElement || element == importElement.getImportReferenceExpression()){
return statement;
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
index b6fed8d9a065..589a7a541035 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
@@ -24,7 +24,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import java.util.Set;
/**
* @author yole
@@ -157,12 +156,12 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl flags = PyUtil.detectDecorationsAndWrappersOf(func);
- if (params [0] == this && !flags.contains(PyFunction.Flag.STATICMETHOD)) {
+ final PyFunction.Modifier modifier = func.getModifier();
+ if (params [0] == this && modifier != PyFunction.Modifier.STATICMETHOD) {
// must be 'self' or 'cls'
final PyClass containingClass = func.getContainingClass();
if (containingClass != null) {
- return new PyClassType(containingClass, flags.contains(PyFunction.Flag.CLASSMETHOD));
+ return new PyClassType(containingClass, modifier == PyFunction.Modifier.CLASSMETHOD);
}
}
if (isKeywordContainer()) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyQualifiedReference.java
similarity index 98%
rename from python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java
rename to python/src/com/jetbrains/python/psi/impl/PyQualifiedReference.java
index 6c01a18db934..c0be37ce5362 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyQualifiedReferenceImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyQualifiedReference.java
@@ -36,8 +36,8 @@ import java.util.*;
/**
* @author yole
*/
-public class PyQualifiedReferenceImpl extends PyReferenceImpl {
- public PyQualifiedReferenceImpl(PyQualifiedExpression element, PyResolveContext context) {
+public class PyQualifiedReference extends PyReferenceImpl {
+ public PyQualifiedReference(PyQualifiedExpression element, PyResolveContext context) {
super(element, context);
}
@@ -344,9 +344,9 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl {
}
private static Collection collectAssignedAttributes(PyQualifiedExpression qualifier) {
- List qualifier_path = PyResolveUtil.unwindQualifiersAsStrList(qualifier);
- if (qualifier_path != null) {
- AssignmentCollectProcessor proc = new AssignmentCollectProcessor(qualifier_path);
+ PyQualifiedName qualifierPath = PyQualifiedName.fromReferenceChain(PyResolveUtil.unwindQualifiers(qualifier));
+ if (qualifierPath != null) {
+ AssignmentCollectProcessor proc = new AssignmentCollectProcessor(qualifierPath);
PyResolveUtil.treeCrawlUp(proc, qualifier);
return proc.getResult();
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
index 4ac10960986a..fed3dace6786 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
@@ -59,7 +59,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
}
}
if (PsiTreeUtil.getParentOfType(this, PyImportElement.class, PyFromImportStatement.class) != null) {
- return new PyImportReferenceImpl(this, context);
+ return new PyImportReference(this, context);
}
if (file != null) {
@@ -74,7 +74,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
}
if (qualifier != null) {
- return new PyQualifiedReferenceImpl(this, context);
+ return new PyQualifiedReference(this, context);
}
return new PyReferenceImpl(this, context);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java
index 32e16b817902..c8d4e4fab387 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java
@@ -2,7 +2,6 @@ package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
-import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.HashSet;
@@ -29,9 +28,9 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo
@NotNull
public Iterable iterateNames() {
if (getParent() instanceof PyFromImportStatement) {
- PyFromImportStatement import_from_stmt = (PyFromImportStatement)getParent();
- PyReferenceExpression from_src = import_from_stmt.getImportSource();
- final List importedFiles = ResolveImportUtil.resolveImportReference(from_src);
+ PyFromImportStatement fromImportStatement = (PyFromImportStatement)getParent();
+ final List importedFiles = ResolveImportUtil.resolveFromOrForeignImport(fromImportStatement,
+ fromImportStatement.getImportSourceQName());
ChainIterable chain = new ChainIterable();
for (PsiElement importedFile : new HashSet(importedFiles)) { // resolver gives lots of duplicates
final PsiElement source = PyUtil.turnDirIntoInit(importedFile);
@@ -50,9 +49,9 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo
return null;
}
if (getParent() instanceof PyFromImportStatement) {
- PyFromImportStatement import_from_stmt = (PyFromImportStatement)getParent();
- PyReferenceExpression from_src = import_from_stmt.getImportSource();
- final List importedFiles = ResolveImportUtil.resolveImportReference(from_src);
+ PyFromImportStatement fromImportStatement = (PyFromImportStatement)getParent();
+ final List importedFiles = ResolveImportUtil.resolveFromOrForeignImport(fromImportStatement,
+ fromImportStatement.getImportSourceQName());
for (PsiElement importedFile : new HashSet(importedFiles)) { // resolver gives lots of duplicates
final PsiElement source = PyUtil.turnDirIntoInit(importedFile);
if (source instanceof PyFile) {
@@ -80,11 +79,11 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo
return new ItemPresentation() {
private String getName() {
- PyElement elt = PsiTreeUtil.getParentOfType(PyStarImportElementImpl.this, PyFromImportStatement.class);
- if (elt instanceof PyFromImportStatement) { // always? who knows :)
- PyReferenceExpression imp_src = ((PyFromImportStatement)elt).getImportSource();
+ PyFromImportStatement elt = PsiTreeUtil.getParentOfType(PyStarImportElementImpl.this, PyFromImportStatement.class);
+ if (elt != null) { // always? who knows :)
+ PyReferenceExpression imp_src = elt.getImportSource();
if (imp_src != null) {
- return PyResolveUtil.toPath(imp_src, ".");
+ return PyResolveUtil.toPath(imp_src);
}
}
return ">";
@@ -95,7 +94,7 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo
}
public String getLocationString() {
- StringBuffer buf = new StringBuffer("| ");
+ StringBuilder buf = new StringBuilder("| ");
buf.append("from ").append(getName()).append(" import *");
return buf.toString();
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
index 603cab69adb3..f02b38a3cdb5 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
@@ -402,7 +402,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl my_qualifier;
- List my_result;
- Set my_seen_names;
+ private final PyQualifiedName myQualifier;
+ private final List myResult;
+ private final Set mySeenNames;
/**
* Creates an instance to collect assignments of attributes to the object identified by 'qualifier'.
@@ -28,11 +29,11 @@ public class AssignmentCollectProcessor implements PsiScopeProcessor {
*
* @param qualifier qualifying names, outermost first; must not be empty.
*/
- public AssignmentCollectProcessor(@NotNull List qualifier) {
- assert qualifier.size() > 0;
- my_qualifier = qualifier;
- my_result = new ArrayList();
- my_seen_names = new HashSet();
+ public AssignmentCollectProcessor(@NotNull PyQualifiedName qualifier) {
+ assert qualifier.getComponentCount() > 0;
+ myQualifier = qualifier;
+ myResult = new ArrayList();
+ mySeenNames = new HashSet();
}
public boolean execute(final PsiElement element, final ResolveState state) {
@@ -41,19 +42,19 @@ public class AssignmentCollectProcessor implements PsiScopeProcessor {
for (PyExpression ex : assignment.getTargets()) {
if (ex instanceof PyTargetExpression) {
final PyTargetExpression target = (PyTargetExpression)ex;
- List quals = PyResolveUtil.unwindQualifiersAsStrList(target);
List qualsExpr = PyResolveUtil.unwindQualifiers(target);
- if (quals != null) {
- if (quals.size() == my_qualifier.size() + 1 && PyResolveUtil.pathsMatchStr(quals, my_qualifier)) {
+ PyQualifiedName qualifiedName = PyQualifiedName.fromReferenceChain(qualsExpr);
+ 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();
- if (!my_seen_names.contains(last_elt_name)) { // no dupes, only remember the latest
- my_result.add(last_elt);
- my_seen_names.add(last_elt_name);
+ if (!mySeenNames.contains(last_elt_name)) { // no dupes, only remember the latest
+ myResult.add(last_elt);
+ mySeenNames.add(last_elt_name);
}
}
- else if (quals.size() < my_qualifier.size() + 1 && PyResolveUtil.pathsMatchStr(my_qualifier, quals)) {
+ else if (qualifiedName.getComponentCount() < myQualifier.getComponentCount() + 1 && myQualifier.matchesPrefix(qualifiedName)) {
// qualifier(s) get redefined; collect no more.
return false;
}
@@ -66,12 +67,12 @@ public class AssignmentCollectProcessor implements PsiScopeProcessor {
}
/**
- * @return a collection of exressions (parts of assignment expressions) where new attributes were defined. E.g. for "a.b.c = 1",
+ * @return a collection of expressions (parts of assignment expressions) where new attributes were defined. E.g. for "a.b.c = 1",
* the expression for 'c' is in the result.
*/
@NotNull
public Collection getResult() {
- return my_result;
+ return myResult;
}
public T getHint(final Key hintKey) {
diff --git a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
index ce561f20aab1..9df00aedcbf6 100644
--- a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
+++ b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
@@ -15,11 +15,11 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.impl.PyQualifiedName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -232,57 +232,13 @@ public class PyResolveUtil {
return treeCrawlUp(processor, false, elt);
}
-
- /**
- * Tries to match two [qualified] reference expression paths by names; target must be a 'sublist' of source to match.
- * E.g., 'a.b.c.d' and 'a.b.c' would match, while 'a.b.c' and 'a.b.c.d' would not. Eqaully, 'a.b.c' and 'a.b.d' would not match.
- * If either source or target is null, false is returned.
- *
- * @param source_path expression path to match (the longer list of qualifiers).
- * @param target_path expression path to match against (hopeful sublist of qualifiers of source).
- * @return true if source matches target.
- * @see #unwindQualifiers(PyQualifiedExpression) .
- */
- public static boolean pathsMatch(List source_path, List target_path) {
- // turn qualifiers into lists
- if ((source_path == null) || (target_path == null)) return false;
- // compare until target is exhausted
- Iterator source_iter = source_path.iterator();
- for (final T target_elt : target_path) {
- if (source_iter.hasNext()) {
- S source_elt = source_iter.next();
- if (!target_elt.getText().equals(source_elt.getText())) return false;
- }
- else {
- return false;
- } // source exhausted before target
- }
- return true;
- }
-
- public static boolean pathsMatchStr(List source_path, List target_path) {
- // turn qualifiers into lists
- if ((source_path == null) || (target_path == null)) return false;
- // compare until target is exhausted
- Iterator source_iter = source_path.iterator();
- for (final String target_elt : target_path) {
- if (source_iter.hasNext()) {
- String source_elt = source_iter.next();
- if (!target_elt.equals(source_elt)) return false;
- }
- else {
- return false;
- } // source exhausted before target
- }
- return true;
- }
-
/**
* Unwinds a multi-level qualified expression into a path, as seen in source text, i.e. outermost qualifier first.
*
- * @param expr an experssion to unwind.
+ * @param expr an expression to unwind.
* @return path as a list of ref expressions.
*/
+ @NotNull
public static List unwindQualifiers(final PyQualifiedExpression expr) {
final List path = new LinkedList();
PyQualifiedExpression e = expr;
@@ -305,27 +261,18 @@ public class PyResolveUtil {
return path;
}
- public static String toPath(PyQualifiedExpression expr, String separator) {
+ public static String toPath(PyQualifiedExpression expr) {
if (expr == null) return "";
List path = unwindQualifiers(expr);
- if (path != null) {
- StringBuilder buf = new StringBuilder();
- boolean is_not_first = false;
- for (PyExpression ex : path) {
- if (is_not_first) {
- buf.append(separator);
- }
- else {
- is_not_first = true;
- }
- buf.append(ex.getName());
- }
- return buf.toString();
+ final PyQualifiedName qName = PyQualifiedName.fromReferenceChain(path);
+ if (qName != null) {
+ return qName.toString();
}
- else {
- String s = expr.getName();
- return s != null ? s : "";
+ String name = expr.getName();
+ if (name != null) {
+ return name;
}
+ return "";
}
/**
diff --git a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java
new file mode 100644
index 000000000000..b57d36ec28d2
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java
@@ -0,0 +1,277 @@
+package com.jetbrains.python.psi.resolve;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.intellij.facet.FacetManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.jetbrains.django.facet.DjangoFacetType;
+import com.jetbrains.python.console.PydevConsoleRunner;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
+import com.jetbrains.python.psi.impl.PyQualifiedName;
+import com.jetbrains.python.sdk.PythonSdkType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Resolves the specified qualified name in the specified context (module, all modules or a file) to a file or directory.
+ *
+ * @author yole
+ */
+public class QualifiedNameResolver implements RootVisitor {
+ boolean myCheckForPackage = true;
+ @Nullable private Module myModule;
+ private PsiFile myFootholdFile;
+ private final @NotNull PyQualifiedName myQualifiedName;
+ @NotNull PsiManager myPsiManager;
+ final Set results = Sets.newLinkedHashSet();
+ private boolean myAcceptRootAsTopLevelPackage;
+ private boolean myVisitAllModules = false;
+ private int myRelativeLevel = -1;
+ private boolean myWithoutRoots;
+ private Sdk myWithSdk;
+
+ public QualifiedNameResolver(@NotNull String qNameString) {
+ myQualifiedName = PyQualifiedName.fromDottedString(qNameString);
+ }
+
+ public QualifiedNameResolver(@NotNull PyQualifiedName qName) {
+ myQualifiedName = qName;
+ }
+
+ public QualifiedNameResolver fromElement(@NotNull PsiElement foothold) {
+ myFootholdFile = foothold.getContainingFile().getOriginalFile();
+ myPsiManager = PsiManager.getInstance(foothold.getProject());
+ setModule(ModuleUtil.findModuleForPsiElement(myFootholdFile));
+ if (PydevConsoleRunner.isInPydevConsole(foothold)) {
+ withAllModules();
+ }
+ return this;
+ }
+
+ public QualifiedNameResolver fromModule(@NotNull Module module) {
+ setModule(module);
+ myPsiManager = PsiManager.getInstance(module.getProject());
+ return this;
+ }
+
+ private void setModule(@Nullable Module module) {
+ myModule = module;
+ if (module != null && FacetManager.getInstance(module).getFacetByType(DjangoFacetType.ID) != null) {
+ myAcceptRootAsTopLevelPackage = true;
+ }
+ }
+
+ public QualifiedNameResolver withAllModules() {
+ myVisitAllModules = true;
+ return this;
+ }
+
+ /**
+ * Specifies that we need to look for the name in the specified SDK (instead of the SDK assigned to the module, if any).
+ *
+ * @param sdk the SDK in which the name should be searched.
+ * @return this
+ */
+ public QualifiedNameResolver withSdk(Sdk sdk) {
+ myWithSdk = sdk;
+ return this;
+ }
+
+ /**
+ * Specifies whether we should attempt to resolve imports relative to the current file.
+ *
+ * @param relativeLevel if >= 0, we try to resolve at the specified number of levels above the current file.
+ * @return this
+ */
+ public QualifiedNameResolver withRelative(int relativeLevel) {
+ myRelativeLevel = relativeLevel;
+ return this;
+ }
+
+ /**
+ * Specifies that we should only try to resolve relative to the current file, not in roots.
+ *
+ * @return this
+ */
+ public QualifiedNameResolver withoutRoots() {
+ myWithoutRoots = true;
+ return this;
+ }
+
+ /**
+ * Specifies that we're looking for a file in a directory hierarchy, not a module in the Python package hierarchy
+ * (so we don't need to check for existence of __init__.py)
+ *
+ * @return
+ */
+ public QualifiedNameResolver withPlainDirectories() {
+ myCheckForPackage = false;
+ return this;
+ }
+
+ public boolean visitRoot(final VirtualFile root) {
+ if (!root.isValid()) {
+ return true;
+ }
+ PsiElement module = resolveInRoot(root);
+ if (module != null) {
+ results.add(module);
+ }
+
+ if (myAcceptRootAsTopLevelPackage && myQualifiedName.matchesPrefix(PyQualifiedName.fromDottedString(root.getName()))) {
+ module = resolveInRoot(root.getParent());
+ if (module != null) {
+ results.add(module);
+ }
+ }
+
+ return true;
+ }
+
+ @NotNull
+ public List resultsAsList() {
+ if (myFootholdFile != null && !myFootholdFile.isValid()) {
+ return Collections.emptyList();
+ }
+
+ if (myRelativeLevel >= 0) {
+ assert myFootholdFile != null;
+ PsiDirectory dir = myFootholdFile.getContainingDirectory();
+ if (myRelativeLevel > 0) {
+ dir = ResolveImportUtil.stepBackFrom(myFootholdFile, myRelativeLevel);
+
+ }
+ PsiElement module = resolveModuleAt(dir, null);
+ if (module != null) {
+ results.add(module);
+ }
+ }
+
+ if (!myWithoutRoots) {
+ PythonPathCache cache = findMyCache();
+ if (cache != null) {
+ final List cachedResults = cache.get(myQualifiedName);
+ if (cachedResults != null) {
+ return cachedResults;
+ }
+ }
+
+ if (myVisitAllModules) {
+ for (Module mod : ModuleManager.getInstance(myPsiManager.getProject()).getModules()) {
+ RootVisitorHost.visitRoots(mod, false, this);
+ }
+ }
+ else if (myModule != null) {
+ final boolean otherSdk = withOtherSdk();
+ RootVisitorHost.visitRoots(myModule, otherSdk, this);
+ if (otherSdk) {
+ RootVisitorHost.visitSdkRoots(myWithSdk, this);
+ }
+ }
+ else if (myFootholdFile != null) {
+ RootVisitorHost.visitSdkRoots(myFootholdFile, this);
+ }
+ else {
+ throw new IllegalStateException();
+ }
+
+ final ArrayList resultList = Lists.newArrayList(results);
+ if (cache != null) {
+ cache.put(myQualifiedName, resultList);
+ }
+ return resultList;
+ }
+
+ return Lists.newArrayList(results);
+ }
+
+ @Nullable
+ public PsiElement firstResult() {
+ final List results = resultsAsList();
+ return results.size() > 0 ? results.get(0) : null;
+ }
+
+ @NotNull
+ public List resultsOfType(Class clazz) {
+ List result = new ArrayList();
+ for (PsiElement element : resultsAsList()) {
+ if (clazz.isInstance(element)) {
+ //noinspection unchecked
+ result.add((T) element);
+ }
+ }
+ return result;
+ }
+
+ @Nullable
+ public T firstResultOfType(Class clazz) {
+ final List list = resultsOfType(clazz);
+ return list.size() > 0 ? list.get(0) : null;
+ }
+
+ private boolean withOtherSdk() {
+ return myWithSdk != null && myWithSdk != PythonSdkType.findPythonSdk(myModule);
+ }
+
+ @Nullable
+ private PythonPathCache findMyCache() {
+ if (myVisitAllModules) {
+ return null;
+ }
+ if (myModule != null) {
+ return withOtherSdk() ? null : PythonModulePathCache.getInstance(myModule);
+ }
+ if (myFootholdFile != null) {
+ final Sdk sdk = PyBuiltinCache.findSdkForFile(myFootholdFile);
+ if (sdk != null) {
+ return PythonSdkPathCache.getInstance(myPsiManager.getProject(), sdk);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private PsiElement resolveInRoot(VirtualFile root) {
+ if (!root.isDirectory()) {
+ // if we have added a file as a root, it's unlikely that we'll be able to resolve anything under it in 'files only' resolve mode
+ return null;
+ }
+ return resolveModuleAt(myPsiManager.findDirectory(root), root);
+ }
+
+ /**
+ * Searches for a module at given directory, unwinding qualifiers and traversing directories as needed.
+ *
+ * @param directory where to start from; top qualifier will be searched for here.
+ * @param root an SDK, library or content root from which we're searching, or null if we're searching relatively
+ * @return module's file, or null.
+ */
+ @Nullable
+ private PsiElement resolveModuleAt(@Nullable PsiDirectory directory, @Nullable VirtualFile root) {
+ // prerequisites
+ if (directory == null || !directory.isValid()) return null;
+
+ PsiElement seeker = directory;
+ for (String name : myQualifiedName.getComponents()) {
+ if (name == null) {
+ return null;
+ }
+ seeker = ResolveImportUtil.resolveChild(seeker, name, myFootholdFile, root, true, myCheckForPackage);
+ }
+ return seeker;
+ }
+
+}
diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java
index 506f66ee2ee8..39ec7d59ce81 100644
--- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java
+++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java
@@ -1,11 +1,7 @@
package com.jetbrains.python.psi.resolve;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.intellij.facet.FacetManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
@@ -15,11 +11,8 @@ import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
-import com.jetbrains.django.facet.DjangoFacetType;
import com.jetbrains.python.PyNames;
-import com.jetbrains.python.console.PydevConsoleRunner;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyFileImpl;
@@ -29,7 +22,10 @@ import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import static com.jetbrains.python.psi.FutureFeature.ABSOLUTE_IMPORT;
@@ -113,7 +109,7 @@ public class ResolveImportUtil {
}
@NotNull
- private static List multiResolveImportElement(PyImportElement import_element, final PyQualifiedName qName) {
+ public static List multiResolveImportElement(PyImportElement import_element, final PyQualifiedName qName) {
if (qName == null) return Collections.emptyList();
// TODO: search for entire names, not for first component only!
@@ -160,28 +156,6 @@ public class ResolveImportUtil {
return result != null ? Collections.singletonList(result) : Collections.emptyList();
}
- @NotNull
- public static List resolveImportReference(final PyReferenceExpression importRef) {
- // prerequisites
- if (importRef == null) return Collections.emptyList();
- if (!importRef.isValid()) return Collections.emptyList(); // we often catch a reparse while in a process of resolution
- final String referencedName = importRef.getReferencedName(); // it will be the "foo" in later comments
- if (referencedName == null) return Collections.emptyList();
- final PsiFile file = importRef.getContainingFile();
- if (file == null || !file.isValid()) return Collections.emptyList();
-
- final PyElement parent = PsiTreeUtil.getParentOfType(importRef, PyImportElement.class, PyFromImportStatement.class); //importRef.getParent();
- final PyQualifiedName qname = importRef.asQualifiedName();
- if (parent instanceof PyImportElement) {
- PyImportElement import_element = (PyImportElement)parent;
- return multiResolveImportElement(import_element, qname);
- }
- else if (parent instanceof PyFromImportStatement) { // "from foo import"
- return resolveFromOrForeignImport((PyFromImportStatement)parent, qname);
- }
- return Collections.emptyList();
- }
-
public static List resolveFromOrForeignImport(PyFromImportStatement fromImportStatement, PyQualifiedName qname) {
final List results = resolveFromImportStatementSource(fromImportStatement, qname);
if (results.isEmpty() && qname != null && qname.getComponentCount() > 0) {
@@ -215,152 +189,41 @@ public class ResolveImportUtil {
*
* @param qualifiedName qualified name of the module reference to resolve
* @param source_file where that reference resides; serves as PSI foothold to determine module, project, etc.
- * @param import_is_absolute if false, try old python 2.x's "relative first, absolute next" approach.
- * @param relative_level if > 0, step back from source_file and resolve from there (even if import_is_absolute is false!).
+ * @param importIsAbsolute if false, try old python 2.x's "relative first, absolute next" approach.
+ * @param relativeLevel if > 0, step back from source_file and resolve from there (even if importIsAbsolute is false!).
* @return list of possible candidates
*/
@NotNull
public static List resolveModule(@Nullable PyQualifiedName qualifiedName, PsiFile source_file,
- boolean import_is_absolute, int relative_level) {
+ boolean importIsAbsolute, int relativeLevel) {
if (qualifiedName == null) return Collections.emptyList();
- String marker = StringUtil.join(qualifiedName.getComponents(), ".") + "#" + Integer.toString(relative_level);
+ String marker = StringUtil.join(qualifiedName.getComponents(), ".") + "#" + Integer.toString(relativeLevel);
Set being_imported = ourBeingImported.get();
if (being_imported.contains(marker)) return Collections.emptyList(); // break endless loop in import
try {
being_imported.add(marker);
- if (relative_level > 0) {
+ QualifiedNameResolver visitor = new QualifiedNameResolver(qualifiedName).fromElement(source_file);
+ if (relativeLevel > 0) {
// "from ...module import"
- final PsiElement module = resolveModuleAt(stepBackFrom(source_file, relative_level), source_file, qualifiedName);
- return module != null ? Collections.singletonList(module) : Collections.emptyList();
+ visitor.withRelative(relativeLevel).withoutRoots();
}
else { // "from module import"
- if (import_is_absolute) {
- return resolveModulesInRoots(qualifiedName, source_file);
- }
- else {
- final PsiDirectory dir = source_file.getOriginalFile().getContainingDirectory();
- PsiElement module = resolveModuleAt(dir, source_file, qualifiedName);
- if (module != null) {
- return Collections.singletonList(module);
- }
- List found_in_roots = resolveModulesInRoots(qualifiedName, source_file);
- if (found_in_roots.size() > 0) return found_in_roots;
-
- return Collections.emptyList();
+ if (!importIsAbsolute) {
+ visitor.withRelative(0);
}
}
+ return visitor.resultsAsList();
}
finally {
being_imported.remove(marker);
}
}
- /**
- * Searches for a module at given directory, unwinding qualifiers and traversing directories as needed.
- *
- * @param directory where to start from; top qualifier will be searched for here.
- * @param sourceFile the file containing the import statement being resolved
- * @param qualifiedName the qualified name of the module to search
- * @return module's file, or null.
- */
- @Nullable
- private static PsiElement resolveModuleAt(PsiDirectory directory, PsiFile sourceFile, PyQualifiedName qualifiedName) {
- // prerequisites
- if (directory == null || !directory.isValid()) return null;
- if (sourceFile == null || !sourceFile.isValid()) return null;
-
- PsiElement seeker = directory;
- for (String name : qualifiedName.getComponents()) {
- if (name == null) {
- return null;
- }
- seeker = resolveChild(seeker, name, sourceFile, null, true, true);
- }
- return seeker;
- }
-
@Nullable
public static PsiElement resolveModuleInRoots(@NotNull PyQualifiedName moduleQualifiedName, @Nullable PsiElement foothold) {
- final List candidates = resolveModulesInRoots(moduleQualifiedName, foothold);
- return candidates.isEmpty() ? null : candidates.get(0);
- }
-
- /**
- * Returns the list of directories/files under different project roots which match the specified qualified name.
- *
- * @param moduleQualifiedName the qualified name to find
- * @param foothold the PSI element in the context of which the search is performed
- * @return the list of matching directories or files, or an empty list if nothing was found
- */
- @NotNull
- public static List resolveModulesInRoots(@NotNull PyQualifiedName moduleQualifiedName, @Nullable PsiElement foothold) {
- if (foothold == null || !foothold.isValid()) return Collections.emptyList();
- PsiFile footholdFile = foothold.getContainingFile();
- if (footholdFile == null || !footholdFile.isValid()) return Collections.emptyList();
-
- PythonPathCache cache = getPathCache(foothold);
- if (cache != null) {
- final List cachedResults = cache.get(moduleQualifiedName);
- if (cachedResults != null) {
- return cachedResults;
- }
- }
-
- final Module module = ModuleUtil.findModuleForPsiElement(foothold);
-
- List results;
-
- if (PydevConsoleRunner.isInPydevConsole(foothold)) {
- results = visitRootsInAllModules(moduleQualifiedName, foothold, footholdFile);
- }
- else {
- results = visitRoots(moduleQualifiedName, foothold.getManager(), module, foothold, true);
- }
-
- if (cache != null) {
- cache.put(moduleQualifiedName, results);
- }
- return results;
- }
-
- private static List visitRootsInAllModules(PyQualifiedName moduleQualifiedName, PsiElement foothold, PsiFile footholdFile) {
- Set res = Sets.newHashSet();
- for (Module mod : ModuleManager.getInstance(footholdFile.getProject()).getModules()) {
- res.addAll(visitRoots(moduleQualifiedName, foothold.getManager(), mod, foothold, true));
- }
- return Lists.newArrayList(res);
- }
-
- private static List visitRoots(@NotNull PyQualifiedName moduleQualifiedName,
- @NotNull PsiManager manager,
- @Nullable Module module,
- @Nullable PsiElement foothold,
- boolean checkForPackage) {
-
- PsiFile footholdFile = foothold != null ? foothold.getContainingFile() : null;
- boolean has_djando_facet = false;
- if (module != null) {
- has_djando_facet = FacetManager.getInstance(module).getFacetByType(DjangoFacetType.ID) != null;
- }
- ResolveInRootVisitor visitor;
- // resolve the name considering every source root as a package dir, as if it's a deployed package. django console does so.
- if (has_djando_facet) {
- visitor = new ResolveInRootAsTopPackageVisitor(moduleQualifiedName, manager, footholdFile, checkForPackage);
- }
- else {
- visitor = new ResolveInRootVisitor(moduleQualifiedName, manager, footholdFile, checkForPackage);
- }
- if (module != null) {
- visitRoots(module, visitor);
- return visitor.resultsAsList();
- }
- else if (foothold != null) {
- visitSdkRoots(foothold, visitor);
- return visitor.resultsAsList();
- }
- else {
- throw new IllegalStateException();
- }
+ if (foothold == null) return null;
+ QualifiedNameResolver visitor = new QualifiedNameResolver(moduleQualifiedName).fromElement(foothold);
+ return visitor.firstResult();
}
@Nullable
@@ -379,175 +242,6 @@ public class ResolveImportUtil {
return cache;
}
- @NotNull
- public static List resolveModulesInRoots(@NotNull Module module, @NotNull PyQualifiedName moduleQualifiedName,
- boolean checkForPackage) {
- PythonPathCache cache = PythonModulePathCache.getInstance(module);
- final List cachedResults = cache.get(moduleQualifiedName);
- if (cachedResults != null) {
- return cachedResults;
- }
- List results = visitRoots(moduleQualifiedName, PsiManager.getInstance(module.getProject()), module, null, checkForPackage);
- cache.put(moduleQualifiedName, results);
- return results;
- }
-
- @NotNull
- public static List resolveModulesInRootProvider(@NotNull RootProvider rootProvider,
- @NotNull Module module,
- @NotNull PyQualifiedName moduleQualifiedName) {
- ResolveInRootVisitor visitor = new ResolveInRootVisitor(moduleQualifiedName, PsiManager.getInstance(module.getProject()), null,
- true);
- if (visitModuleContentEntries(ModuleRootManager.getInstance(module), visitor)) {
- for (VirtualFile file : rootProvider.getFiles(OrderRootType.CLASSES)) {
- visitor.visitRoot(file);
- }
- }
- return visitor.resultsAsList();
- }
-
- public static void visitRoots(@NotNull final PsiElement elt, @NotNull final RootVisitor visitor) {
- // real search
- final Module module = ModuleUtil.findModuleForPsiElement(elt);
- if (module != null) {
- visitRoots(module, visitor);
- }
- else {
- visitSdkRoots(elt, visitor);
- }
- }
-
- public static void visitRoots(@NotNull Module module, final RootVisitor visitor) {
- OrderEnumerator.orderEntries(module).recursively().forEach(new Processor() {
- @Override
- public boolean process(OrderEntry orderEntry) {
- if (orderEntry instanceof ModuleSourceOrderEntry) {
- return visitModuleContentEntries(((ModuleSourceOrderEntry)orderEntry).getRootModel(), visitor);
- }
- return visitOrderEntryRoots(visitor, orderEntry);
- }
- });
- }
-
- /**
- * Visits module content, sdk roots and libraries
- */
- public static void visitRoots(@NotNull Module module, @NotNull Sdk sdk, RootVisitor visitor) {
- if (!visitModuleContentEntries(ModuleRootManager.getInstance(module), visitor)) return;
- // else look in SDK roots
- if (visitSdkRoots(visitor, sdk)) return;
-
- //look in libraries
- ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
- rootManager.orderEntries().process(new LibraryRootVisitingPolicy(visitor), null);
- }
-
- private static void visitSdkRoots(PsiElement elt, RootVisitor visitor) {
- // no module, another way to look in SDK roots
- final PsiFile elt_psifile = elt.getContainingFile();
- if (elt_psifile != null) { // formality
- final VirtualFile elt_vfile = elt_psifile.getOriginalFile().getVirtualFile();
- List orderEntries = null;
- if (elt_vfile != null) { // reality
- final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(elt.getProject()).getFileIndex();
- orderEntries = fileIndex.getOrderEntriesForFile(elt_vfile);
- if (orderEntries.size() > 0) {
- for (OrderEntry entry : orderEntries) {
- if (!visitOrderEntryRoots(visitor, entry)) break;
- }
- }
- else {
- orderEntries = null;
- }
- }
-
- // out-of-project file or non-file(e.g. console) - use roots of SDK assigned to project
- if (orderEntries == null) {
- final Sdk sdk = ProjectRootManager.getInstance(elt.getProject()).getProjectSdk();
- if (sdk != null) {
- visitSdkRoots(visitor, sdk);
- }
- }
- }
- }
-
- private static boolean visitSdkRoots(@NotNull RootVisitor visitor, @NotNull Sdk sdk) {
- final VirtualFile[] roots = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
- for (VirtualFile root : roots) {
- if (!visitor.visitRoot(root)) {
- return true;
- }
- }
- return false;
- }
-
-
- private static boolean visitModuleContentEntries(ModuleRootModel rootModel, RootVisitor visitor) {
- // look in module sources
- Set contentRoots = Sets.newHashSet();
- for (ContentEntry entry : rootModel.getContentEntries()) {
- VirtualFile rootFile = entry.getFile();
-
- if (rootFile != null && !visitor.visitRoot(rootFile)) return false;
- contentRoots.add(rootFile);
- for (VirtualFile folder : entry.getSourceFolderFiles()) {
- if (!visitor.visitRoot(folder)) return false;
- }
- }
- return true;
- }
-
- private static boolean visitOrderEntryRoots(RootVisitor visitor, OrderEntry entry) {
- Set allRoots = new LinkedHashSet();
- Collections.addAll(allRoots, entry.getFiles(OrderRootType.SOURCES));
- Collections.addAll(allRoots, entry.getFiles(OrderRootType.CLASSES));
- for (VirtualFile root : allRoots) {
- if (!visitor.visitRoot(root)) {
- return false;
- }
- }
- return true;
- }
-
- @Nullable
- public static PsiElement resolveInRoots(@NotNull final PsiElement context, final String name) {
- return resolveInRoots(context, PyQualifiedName.fromDottedString(name));
- }
-
- /**
- * Looks for a name among element's module's roots; if there's no module, then among project's roots.
- *
- * @param context PSI element that defines the module and/or the project.
- * @param qualifiedName module name to be found among roots.
- * @return a PsiFile, a child of a root.
- */
- @Nullable
- public static PsiElement resolveInRoots(@NotNull final PsiElement context, final PyQualifiedName qualifiedName) {
- // NOTE: a quick and dirty temporary fix for "current dir" root path, which is assumed to be present first (but may be not).
- if (qualifiedName.getComponentCount() == 1) {
- PsiElement res = resolveInCurrentDir(context, qualifiedName.getLastComponent());
- if (res != null) {
- return res;
- }
- }
- return resolveModuleInRoots(qualifiedName, context);
- }
-
- @Nullable
- public static PsiElement resolveInCurrentDir(@NotNull final PsiElement elt, final String refName) {
- PsiFile pfile = elt.getContainingFile();
- VirtualFile vfile = pfile.getVirtualFile();
- if (vfile == null) { // we're probably within a copy, e.g. for completion; get the real thing
- pfile = pfile.getOriginalFile();
- }
- PsiDirectory pdir = pfile.getContainingDirectory();
- if (pdir != null) {
- PsiElement child_elt = resolveChild(pdir, refName, pfile, null, true, true);
- if (child_elt != null) return child_elt;
- }
- return null;
- }
-
@Nullable
private static PsiElement resolveForeignImport(@NotNull final PyElement importElement,
@NotNull final PyQualifiedName importText,
@@ -561,99 +255,6 @@ public class ResolveImportUtil {
return null;
}
- public static boolean findInRoots(Module module, Sdk pythonSdk, String name) {
- ResolveNameVisitor
- visitor = new ResolveNameVisitor(PsiManager.getInstance(module.getProject()), name);
- visitRoots(module, pythonSdk, visitor);
- return visitor.isFound();
- }
-
- static class ResolveInRootVisitor implements RootVisitor {
- final PsiFile myFootholdFile;
- final boolean myCheckForPackage;
- final @NotNull PyQualifiedName myQualifiedName;
- final @NotNull PsiManager myPsiManager;
- final Set results = Sets.newLinkedHashSet();
-
- public ResolveInRootVisitor(@NotNull PyQualifiedName qName,
- @NotNull PsiManager psiManager,
- @Nullable PsiFile foothold_file,
- boolean checkForPackage) {
- myQualifiedName = qName;
- myPsiManager = psiManager;
- myFootholdFile = foothold_file;
- myCheckForPackage = checkForPackage;
- }
-
- public boolean visitRoot(final VirtualFile root) {
- if (!root.isValid()) {
- return true;
- }
- PsiElement module = resolveInRoot(root, myQualifiedName, myPsiManager, myFootholdFile, myCheckForPackage);
- if (module != null) {
- results.add(module);
- }
-
- return true;
- }
-
- @NotNull
- public List resultsAsList() {
- return Lists.newArrayList(results);
- }
-
- @Nullable
- protected static PsiElement resolveInRoot(VirtualFile root,
- PyQualifiedName qualifiedName,
- PsiManager psiManager,
- @Nullable PsiFile foothold_file,
- boolean checkForPackage) {
- PsiElement module = root.isDirectory() ? psiManager.findDirectory(root) : psiManager.findFile(root);
- if (module == null) return null;
- for (String component : qualifiedName.getComponents()) {
- if (component == null) {
- module = null;
- break;
- }
- module = resolveChild(module, component, foothold_file, root, false, checkForPackage); // only files, we want a module
- }
- return module;
- }
- }
-
- /**
- * Visits roots and detects if qName is a name of top package coincinding with a root:
- * that is, tha package is not one of root's children, but the root itself.
- */
- private static class ResolveInRootAsTopPackageVisitor extends ResolveInRootVisitor {
- public ResolveInRootAsTopPackageVisitor(@NotNull PyQualifiedName qName,
- @NotNull PsiManager psiManager,
- @Nullable PsiFile foothold_file,
- boolean checkForPackage) {
- super(qName, psiManager, foothold_file, checkForPackage);
- }
-
- @Override
- public boolean visitRoot(VirtualFile root) {
- if (!root.isValid()) {
- return true;
- }
- PsiElement module = resolveInRoot(root, myQualifiedName, myPsiManager, myFootholdFile, myCheckForPackage);
- if (module != null) {
- results.add(module);
- }
-
- if (myQualifiedName.matchesPrefix(PyQualifiedName.fromDottedString(root.getName()))) {
- module = resolveInRoot(root.getParent(), myQualifiedName, myPsiManager, myFootholdFile, myCheckForPackage);
- if (module != null) {
- results.add(module);
- }
- }
-
- return true;
- }
- }
-
/**
* Tries to find referencedName under the parent element. Used to resolve any names that look imported.
* Parent might happen to be a PyFile(__init__.py), then it is treated both as a file and as ist base dir.
@@ -685,7 +286,10 @@ public class ResolveImportUtil {
// OTOH, quite often a module named foo exports a class or function named foo, which is used as a fallback
// by a module one level higher (e.g. curses.set_key). Prefer it to submodule if possible.
- ret = ((PyFileImpl)parent).getElementNamed(referencedName, false);
+ PsiElement elementNamed = ((PyFileImpl)parent).getElementNamed(referencedName, false);
+ if (!fileOnly || PyUtil.instanceOf(elementNamed, PsiFile.class, PsiDirectory.class)) {
+ ret = elementNamed;
+ }
if (ret != null && !PyUtil.instanceOf(ret, PsiFile.class, PsiDirectory.class) &&
PsiTreeUtil.getStubOrPsiParentOfType(ret, PyExceptPart.class) == null) {
return ret;
@@ -865,7 +469,7 @@ public class ResolveImportUtil {
return name;
}
PathChoosingVisitor visitor = new PathChoosingVisitor(vfile);
- visitRoots(foothold, visitor);
+ RootVisitorHost.visitRoots(foothold, visitor);
final PyQualifiedName result = visitor.getResult();
if (cache != null) {
cache.putName(vfile, result);
@@ -881,7 +485,7 @@ public class ResolveImportUtil {
return name.toString();
}
PathChoosingVisitor visitor = new PathChoosingVisitor(vfile);
- visitRoots(module, visitor);
+ RootVisitorHost.visitRoots(module, false, visitor);
final PyQualifiedName result = visitor.getResult();
cache.putName(vfile, result);
return result == null ? null : result.toString();
@@ -964,27 +568,6 @@ public class ResolveImportUtil {
return null;
}
- public static class LibraryRootVisitingPolicy extends RootPolicy {
- private final RootVisitor myVisitor;
-
- public LibraryRootVisitingPolicy(RootVisitor visitor) {
- myVisitor = visitor;
- }
-
- @Nullable
- public PsiElement visitJdkOrderEntry(final JdkOrderEntry jdkOrderEntry, final PsiElement value) {
- return null;
- }
-
- @Nullable
- @Override
- public PsiElement visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, PsiElement value) {
- if (value != null) return value; // for chaining in processOrder()
- visitOrderEntryRoots(myVisitor, libraryOrderEntry);
- return null;
- }
- }
-
/**
* When a name is imported from a module, tries to find the definition of that name inside the module,
* as opposed to looking for submodules.
@@ -1051,34 +634,4 @@ public class ResolveImportUtil {
}
return PointInImport.NONE;
}
-
- public static class ResolveNameVisitor implements RootVisitor {
- final @NotNull PsiManager myPsiManager;
- private boolean myFound = false;
- private final String myName;
-
-
- public ResolveNameVisitor(@NotNull PsiManager psiManager, String name) {
- myPsiManager = psiManager;
- myName = name;
- }
-
- public boolean visitRoot(final VirtualFile root) {
- if (!root.isValid()) {
- return true;
- }
- PsiElement module = root.isDirectory() ? myPsiManager.findDirectory(root) : myPsiManager.findFile(root);
- module = resolveChild(module, myName, null, root, false, false);
- if (module != null) {
- myFound = true;
- return false;
- }
-
- return true;
- }
-
- public boolean isFound() {
- return myFound;
- }
- }
}
diff --git a/python/src/com/jetbrains/python/psi/resolve/RootVisitorHost.java b/python/src/com/jetbrains/python/psi/resolve/RootVisitorHost.java
new file mode 100644
index 000000000000..c6490d97878f
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/resolve/RootVisitorHost.java
@@ -0,0 +1,115 @@
+package com.jetbrains.python.psi.resolve;
+
+import com.google.common.collect.Sets;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.*;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.Processor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author yole
+ */
+public class RootVisitorHost {
+ public static void visitRoots(@NotNull final PsiElement elt, @NotNull final RootVisitor visitor) {
+ // real search
+ final Module module = ModuleUtil.findModuleForPsiElement(elt);
+ if (module != null) {
+ visitRoots(module, false, visitor);
+ }
+ else {
+ final PsiFile containingFile = elt.getContainingFile();
+ if (containingFile != null) {
+ visitSdkRoots(containingFile, visitor);
+ }
+ }
+ }
+
+ public static void visitRoots(@NotNull Module module, final boolean skipSdk, final RootVisitor visitor) {
+ OrderEnumerator enumerator = OrderEnumerator.orderEntries(module).recursively();
+ if (skipSdk) {
+ enumerator = enumerator.withoutSdk();
+ }
+ enumerator.forEach(new Processor() {
+ @Override
+ public boolean process(OrderEntry orderEntry) {
+ if (orderEntry instanceof ModuleSourceOrderEntry) {
+ return visitModuleContentEntries(((ModuleSourceOrderEntry)orderEntry).getRootModel(), visitor);
+ }
+ return visitOrderEntryRoots(visitor, orderEntry);
+ }
+ });
+ }
+
+ static void visitSdkRoots(PsiFile file, RootVisitor visitor) {
+ // formality
+ final VirtualFile elt_vfile = file.getOriginalFile().getVirtualFile();
+ List orderEntries = null;
+ if (elt_vfile != null) { // reality
+ final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(file.getProject()).getFileIndex();
+ orderEntries = fileIndex.getOrderEntriesForFile(elt_vfile);
+ if (orderEntries.size() > 0) {
+ for (OrderEntry entry : orderEntries) {
+ if (!visitOrderEntryRoots(visitor, entry)) break;
+ }
+ }
+ else {
+ orderEntries = null;
+ }
+ }
+
+ // out-of-project file or non-file(e.g. console) - use roots of SDK assigned to project
+ if (orderEntries == null) {
+ final Sdk sdk = ProjectRootManager.getInstance(file.getProject()).getProjectSdk();
+ if (sdk != null) {
+ visitSdkRoots(sdk, visitor);
+ }
+ }
+ }
+
+ public static boolean visitSdkRoots(@NotNull Sdk sdk, @NotNull RootVisitor visitor) {
+ final VirtualFile[] roots = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
+ for (VirtualFile root : roots) {
+ if (!visitor.visitRoot(root)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static boolean visitModuleContentEntries(ModuleRootModel rootModel, RootVisitor visitor) {
+ // look in module sources
+ Set contentRoots = Sets.newHashSet();
+ for (ContentEntry entry : rootModel.getContentEntries()) {
+ VirtualFile rootFile = entry.getFile();
+
+ if (rootFile != null && !visitor.visitRoot(rootFile)) return false;
+ contentRoots.add(rootFile);
+ for (VirtualFile folder : entry.getSourceFolderFiles()) {
+ if (!visitor.visitRoot(folder)) return false;
+ }
+ }
+ return true;
+ }
+
+ static boolean visitOrderEntryRoots(RootVisitor visitor, OrderEntry entry) {
+ Set allRoots = new LinkedHashSet();
+ Collections.addAll(allRoots, entry.getFiles(OrderRootType.SOURCES));
+ Collections.addAll(allRoots, entry.getFiles(OrderRootType.CLASSES));
+ for (VirtualFile root : allRoots) {
+ if (!visitor.visitRoot(root)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java b/python/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java
index cb8a86967412..db6ef38cb0b4 100644
--- a/python/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java
+++ b/python/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java
@@ -2,6 +2,7 @@ package com.jetbrains.python.psi.types;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.codeInsight.PyDynamicMember;
+import com.jetbrains.python.psi.PyClass;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
@@ -26,9 +27,13 @@ public class PyClassMembersProviderBase implements PyClassMembersProvider {
public static PsiElement resolveMemberByName(Collection members,
PyClassType clazz,
String name) {
+ final PyClass pyClass = clazz.getPyClass();
+ if (pyClass == null) {
+ return null;
+ }
for (PyDynamicMember member : members) {
if (member.getName().equals(name)) {
- return member.resolve(clazz.getPyClass());
+ return member.resolve(pyClass);
}
}
return null;
diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java
index 783470bce64a..7a37b1b4cd75 100644
--- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java
+++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java
@@ -16,10 +16,10 @@ import java.util.*;
* @author yole
*/
public class PyUnionType implements PyType {
- private final List myMembers;
+ private final Set myMembers;
private PyUnionType(Collection members) {
- myMembers = new ArrayList(members);
+ myMembers = new LinkedHashSet(members);
}
@Nullable
@@ -132,26 +132,11 @@ public class PyUnionType implements PyType {
return false;
}
- public List getMembers() {
+ public Collection getMembers() {
return myMembers;
}
-
- public List getResolvedMembers(TypeEvalContext context) {
- List result = new ArrayList();
- for (PyType member : myMembers) {
- if (member instanceof PyTypeReference) {
- final PyType resolved = ((PyTypeReference)member).resolve(null, context);
- if (resolved != null && !resolved.equals(this)) {
- result.add(resolved);
- }
- }
- else {
- result.add(member);
- }
- }
- return result;
- }
+ @Nullable
public PyType exclude(PyType t, TypeEvalContext context) {
final List members = new ArrayList();
for (PyType m : getMembers()) {
@@ -172,4 +157,18 @@ public class PyUnionType implements PyType {
return new PyUnionType(Collections.singletonList(type));
}
}
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof PyUnionType) {
+ final PyUnionType otherType = (PyUnionType)other;
+ return myMembers.equals(otherType.myMembers);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return myMembers.hashCode();
+ }
}
diff --git a/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java
index 1a3547657246..9b2181b05aea 100644
--- a/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java
@@ -122,8 +122,8 @@ public class PyIntroduceFieldHandler extends IntroduceHandler {
final PyFunction function = (PyFunction)myScope;
final PyParameter[] parameters = function.getParameterList().getParameters();
if (parameters.length > 0 && result == parameters[0]) {
- final Set flags = PyUtil.detectDecorationsAndWrappersOf(function);
- if (!(flags.contains(PyFunction.Flag.STATICMETHOD))) {
+ final PyFunction.Modifier modifier = function.getModifier();
+ if (modifier != PyFunction.Modifier.STATICMETHOD) {
// 'self' is not a local scope dependency
return;
}
@@ -247,8 +247,8 @@ public class PyIntroduceFieldHandler extends IntroduceHandler {
private static boolean isInStaticMethod(PsiElement element) {
PyFunction containingMethod = PsiTreeUtil.getParentOfType(element, PyFunction.class, false, PyClass.class);
if (containingMethod != null) {
- final Set flags = PyUtil.detectDecorationsAndWrappersOf(containingMethod);
- return flags.contains(PyFunction.Flag.STATICMETHOD);
+ final PyFunction.Modifier modifier = containingMethod.getModifier();
+ return modifier == PyFunction.Modifier.STATICMETHOD;
}
return false;
}
diff --git a/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java
index f53a5536f471..c55013a32ddb 100644
--- a/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java
+++ b/python/src/com/jetbrains/python/sdk/PySkeletonRefresher.java
@@ -103,7 +103,7 @@ public class PySkeletonRefresher {
}
}
- private static String getExtraSysPath(Sdk sdk, String skeletonsPath) {
+ private static String getExtraSysPath(@NotNull Sdk sdk, @Nullable String skeletonsPath) {
final VirtualFile[] classDirs = sdk.getRootProvider().getFiles(OrderRootType.CLASSES);
final StringBuilder builder = new StringBuilder("\"");
int i = 0;
@@ -113,7 +113,7 @@ public class PySkeletonRefresher {
}
if (classDirs[i].isInLocalFileSystem()) {
final String pathname = classDirs[i].getPath();
- if (!skeletonsPath.equals(pathname)) {
+ if (pathname != null && !pathname.equals(skeletonsPath)) {
builder.append(pathname);
}
}
diff --git a/python/src/com/jetbrains/python/sdk/SkeletonErrorsDialog.java b/python/src/com/jetbrains/python/sdk/SkeletonErrorsDialog.java
index 7880cea65399..21ef573b85d2 100644
--- a/python/src/com/jetbrains/python/sdk/SkeletonErrorsDialog.java
+++ b/python/src/com/jetbrains/python/sdk/SkeletonErrorsDialog.java
@@ -1,6 +1,5 @@
package com.jetbrains.python.sdk;
-import com.intellij.openapi.util.Disposer;
import com.intellij.ui.components.JBScrollPane;
import com.jetbrains.python.PyBundle;
@@ -12,8 +11,6 @@ import java.awt.event.ActionListener;
import java.util.List;
import java.util.Map;
-import static java.lang.Math.*;
-
public class SkeletonErrorsDialog extends JDialog {
private JPanel contentPane;
private JButton buttonOK;
@@ -35,8 +32,13 @@ public class SkeletonErrorsDialog extends JDialog {
myMessagePane.setContentType("text/html");
myMessagePane.setBorder(new EmptyBorder(0, 0, 0, 0));
StringBuilder sb = new StringBuilder("");
+ final Color foreground = getParent().getForeground();
+ final Color background = getParent().getBackground();
+ if (foreground != null && background != null) {
+ sb.append("text='").append(getHTMLColor(foreground)).append("' ");
+ sb.append("bgcolor='").append(getHTMLColor(background)).append("'");
+ }
+ sb.append(">");
if (failed_sdks.size() > 0) {
sb.append("").append(PyBundle.message("sdk.error.dialog.failed.sdks")).append("
");
diff --git a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
index e383389310fa..5f7aa526e43f 100644
--- a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
+++ b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
@@ -139,6 +139,9 @@ public class PyStructureViewElement implements StructureViewTreeElement {
private Collection getElementChildren(final PyElement element) {
final Collection children = new ArrayList();
+ if (!element.isValid()) {
+ return children;
+ }
element.acceptChildren(new PyElementVisitor() {
@Override
public void visitElement(PsiElement e) {
diff --git a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java
index 4dbe62cf561a..16009aad9984 100644
--- a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java
@@ -6,8 +6,6 @@ import com.intellij.util.ArrayUtil;
import com.jetbrains.python.highlighting.PyHighlighter;
import com.jetbrains.python.psi.*;
-import java.util.Set;
-
/**
* @author yole
*/
@@ -39,8 +37,8 @@ public class HighlightingAnnotator extends PyAnnotator {
boolean isSelf = false;
final int index = ArrayUtil.find(function.getParameterList().getParameters(), node);
if (function.getContainingClass() != null && index == 0) {
- final Set flags = PyUtil.detectDecorationsAndWrappersOf(function);
- if (!flags.contains(PyFunction.Flag.CLASSMETHOD) && !flags.contains(PyFunction.Flag.STATICMETHOD)) {
+ final PyFunction.Modifier modifier = function.getModifier();
+ if (modifier != PyFunction.Modifier.CLASSMETHOD && modifier != PyFunction.Modifier.STATICMETHOD) {
isSelf = true;
}
}
diff --git a/python/testData/inspections/AddFunctionToModule.py b/python/testData/inspections/AddFunctionToModule.py
index d0426f1db205..db6c9bb36946 100644
--- a/python/testData/inspections/AddFunctionToModule.py
+++ b/python/testData/inspections/AddFunctionToModule.py
@@ -2,4 +2,4 @@ import AddFunctionToModu
# do something
-AddFunctionToModule.frob(1)
+AddFunctionToModule.frob(1)
diff --git a/python/testData/inspections/PyCallByClassInspection/test.py b/python/testData/inspections/PyCallByClassInspection/test.py
index cf72257f7603..e346a34686cf 100644
--- a/python/testData/inspections/PyCallByClassInspection/test.py
+++ b/python/testData/inspections/PyCallByClassInspection/test.py
@@ -4,9 +4,9 @@ class Z(object):
class A(object):
def method(self, *args, **kwargs):
- Z.method(self) # passing wrong instance
- Z.method(Z) # passing class instead of instance
- Z.method(A) # passing class instead of instance AND wrong class
+ Z.method(self) # passing wrong instance
+ Z.method(Z) # passing class instead of instance
+ Z.method(A) # passing class instead of instance AND wrong class
Z.method(Z()) #pass
def __init__(self):
@@ -16,5 +16,4 @@ class B(A):
def __init__(self):
A.__init__(self) # pass
-A.method(B()) # pass
-
+A.method(B())
\ No newline at end of file
diff --git a/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py b/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py
index d10bf20270fe..e0bfc8945642 100644
--- a/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py
+++ b/python/testData/inspections/PyCompatibilityInspection/numericLiteralExpression.py
@@ -1,2 +1,2 @@
a = 12l
-v = 048
\ No newline at end of file
+v = 048
\ No newline at end of file
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/importFunction.py b/python/testData/inspections/PyUnresolvedReferencesInspection/importFunction.py
new file mode 100644
index 000000000000..2bfbaa3d0ee9
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/importFunction.py
@@ -0,0 +1 @@
+import collections.OrderedDict
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py b/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py
index 853423274bc8..6920e61d6f58 100644
--- a/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py
@@ -1 +1 @@
-import wurm
+import wurm
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImportedModule.py b/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImportedModule.py
index 9a9bd1864596..536498f81fad 100644
--- a/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImportedModule.py
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImportedModule.py
@@ -1,2 +1,2 @@
-import deliverance.proxycommand
+import deliverance.proxycommand
deliverance.proxycommand.main()
diff --git a/python/testData/inspections/UnresolvedWith.py b/python/testData/inspections/UnresolvedWith.py
index 135ac77300fa..0f1ee191bdf0 100644
--- a/python/testData/inspections/UnresolvedWith.py
+++ b/python/testData/inspections/UnresolvedWith.py
@@ -1,2 +1,2 @@
-with open("x.txt") as f:
- data = f.read()
\ No newline at end of file
+with open("x.txt") as f:
+ data = f.read()
\ No newline at end of file
diff --git a/python/testData/psi/IncompleteFor.txt b/python/testData/psi/IncompleteFor.txt
index f785bb5d0cc0..3b833e59a2b1 100644
--- a/python/testData/psi/IncompleteFor.txt
+++ b/python/testData/psi/IncompleteFor.txt
@@ -20,7 +20,7 @@ PyFile:IncompleteFor.py
PsiWhiteSpace(' ')
PyReferenceExpression: ba
PsiElement(Py:IDENTIFIER)('ba')
- PsiErrorElement:colon expected
+ PsiErrorElement:Colon expected
PyStatementList
diff --git a/python/testData/psi/IncompleteStatementList.txt b/python/testData/psi/IncompleteStatementList.txt
index 89aa12e134d4..69240089bb12 100644
--- a/python/testData/psi/IncompleteStatementList.txt
+++ b/python/testData/psi/IncompleteStatementList.txt
@@ -15,7 +15,7 @@ PyFile:IncompleteStatementList.py
PsiWhiteSpace(' ')
PyReferenceExpression: ba
PsiElement(Py:IDENTIFIER)('ba')
- PsiErrorElement:colon expected
+ PsiErrorElement:Colon expected
PyStatementList
diff --git a/python/testData/psi/InconsistentDedent.txt b/python/testData/psi/InconsistentDedent.txt
index 1ee44c60498d..2c346adca39b 100644
--- a/python/testData/psi/InconsistentDedent.txt
+++ b/python/testData/psi/InconsistentDedent.txt
@@ -11,7 +11,7 @@ PyFile:InconsistentDedent.py
PyStatementList
PyPassStatement
PsiElement(Py:PASS_KEYWORD)('pass')
- PsiErrorElement:unindent does not match any outer indentation level
+ PsiErrorElement:Unindent does not match any outer indentation level
PsiWhiteSpace('\n ')
PyPrintStatement
diff --git a/python/testData/psi/MissingParenInCall.txt b/python/testData/psi/MissingParenInCall.txt
index 01190ffc3dc4..1021a7a2cb29 100644
--- a/python/testData/psi/MissingParenInCall.txt
+++ b/python/testData/psi/MissingParenInCall.txt
@@ -26,7 +26,7 @@ PyFile:MissingParenInCall.py
PsiElement(Py:COMMA)(',')
PsiErrorElement:expression expected
- PsiErrorElement:colon expected
+ PsiErrorElement:Colon expected
PsiWhiteSpace('\n\n')
PyStatementList
diff --git a/python/testData/psi/WithStatement2.txt b/python/testData/psi/WithStatement2.txt
index e40654dfa532..b5a8e6236750 100644
--- a/python/testData/psi/WithStatement2.txt
+++ b/python/testData/psi/WithStatement2.txt
@@ -72,12 +72,12 @@ PyFile:WithStatement2.py
PyWithItem
PsiErrorElement:expression expected
- PsiErrorElement:colon expected
+ PsiErrorElement:Colon expected
PyStatementList
PsiElement(Py:EQ)('=')
- PsiErrorElement:statement expected, found Py:EQ
+ PsiErrorElement:Statement expected, found Py:EQ
PsiWhiteSpace(' ')
PyExpressionStatement
diff --git a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java
index 196c45ead729..053781491a75 100644
--- a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java
+++ b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java
@@ -1,7 +1,6 @@
package com.jetbrains.python;
import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.psi.*;
@@ -210,14 +209,6 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
assertResolvesTo(PyTargetExpression.class, "__all__");
}
- public void testDunderAllImport() {
- assertResolvesTo(PyTargetExpression.class, "__all__");
- }
-
- public void testDunderAllImportResolve() {
- assertResolvesTo(PyTargetExpression.class, "__all__");
- }
-
public void testDunderAllConflict() {
assertResolvesTo(PyFunction.class, "do_stuff", "/src/mypackage1.py");
}
diff --git a/python/testSrc/com/jetbrains/python/PyResolveCalleeTest.java b/python/testSrc/com/jetbrains/python/PyResolveCalleeTest.java
index 5fc6feac9798..11f591c8b9b4 100644
--- a/python/testSrc/com/jetbrains/python/PyResolveCalleeTest.java
+++ b/python/testSrc/com/jetbrains/python/PyResolveCalleeTest.java
@@ -7,8 +7,6 @@ import com.jetbrains.python.psi.PyCallExpression;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.resolve.PyResolveContext;
-import java.util.EnumSet;
-
/**
* Tests callee resolution in PyCallExpressionImpl.
* User: dcheryasov
@@ -31,7 +29,7 @@ public class PyResolveCalleeTest extends PyTestCase {
public void testClassCall() {
PyCallExpression.PyMarkedCallee resolved = resolveCallee();
assertNotNull(resolved.getCallable());
- assertTrue(resolved.getFlags().equals(EnumSet.noneOf(PyFunction.Flag.class)));
+ assertEquals(null, resolved.getModifier());
}
public void testDecoCall() {
@@ -43,13 +41,13 @@ public class PyResolveCalleeTest extends PyTestCase {
public void testDecoParamCall() {
PyCallExpression.PyMarkedCallee resolved = resolveCallee();
assertNotNull(resolved.getCallable());
- assertTrue(resolved.getFlags().equals(EnumSet.noneOf(PyFunction.Flag.class)));
+ assertNull(resolved.getModifier());
}
public void testWrappedStaticMethod() {
PyCallExpression.PyMarkedCallee resolved = resolveCallee();
assertNotNull(resolved.getCallable());
assertEquals(0, resolved.getImplicitOffset());
- assertEquals(resolved.getFlags(), EnumSet.of(PyFunction.Flag.STATICMETHOD));
+ assertEquals(resolved.getModifier(), PyFunction.Modifier.STATICMETHOD);
}
}
diff --git a/python/testSrc/com/jetbrains/python/PyStubsTest.java b/python/testSrc/com/jetbrains/python/PyStubsTest.java
index 7c069f4cc23d..2abfbea5891c 100644
--- a/python/testSrc/com/jetbrains/python/PyStubsTest.java
+++ b/python/testSrc/com/jetbrains/python/PyStubsTest.java
@@ -21,9 +21,7 @@ import com.jetbrains.python.psi.stubs.PyVariableNameIndex;
import com.jetbrains.python.toolbox.Maybe;
import java.util.Collection;
-import java.util.EnumSet;
import java.util.List;
-import java.util.Set;
/**
* @author max
@@ -335,8 +333,8 @@ public class PyStubsTest extends PyTestCase {
final PyClass pyClass = file.getTopLevelClasses().get(0);
final PyFunction[] methods = pyClass.getMethods();
assertEquals(1, methods.length);
- final Set flags = PyUtil.detectDecorationsAndWrappersOf(methods[0]);
- assertEquals(EnumSet.of(PyFunction.Flag.STATICMETHOD), flags);
+ final PyFunction.Modifier modifier = methods[0].getModifier();
+ assertEquals(PyFunction.Modifier.STATICMETHOD, modifier);
assertNotParsed(file);
}
diff --git a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java
index fac35cef9905..f966b0da1c8b 100644
--- a/python/testSrc/com/jetbrains/python/PyTypeParserTest.java
+++ b/python/testSrc/com/jetbrains/python/PyTypeParserTest.java
@@ -3,7 +3,10 @@ package com.jetbrains.python;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.types.*;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Set;
/**
* @author yole
@@ -44,10 +47,12 @@ public class PyTypeParserTest extends PyTestCase {
public void testUnionType() {
myFixture.configureByFile("typeParser/typeParser.py");
final PyUnionType type = (PyUnionType)PyTypeParser.getTypeByName(myFixture.getFile(), "MyObject or str");
- final List members = type.getMembers();
+ assertNotNull(type);
+ final Collection members = type.getMembers();
assertEquals(2, members.size());
- assertClassType(members.get(0), "MyObject");
- assertClassType(members.get(1), "str");
+ final List list = new ArrayList(members);
+ assertClassType(list.get(0), "MyObject");
+ assertClassType(list.get(1), "str");
}
public void testTypeSubparts() {
diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
index c570c89a73a5..8e7815764422 100644
--- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
@@ -219,7 +219,7 @@ public class PythonInspectionsTest extends PyTestCase {
private void doHighlightingTest(final Class extends PyInspection> inspectionClass) {
myFixture.configureByFile("inspections/" + getTestName(false) + "/test.py");
myFixture.enableInspections(inspectionClass);
- myFixture.checkHighlighting(true, false, false);
+ myFixture.checkHighlighting(true, false, true);
}
private void doHighlightingTest(final Class extends PyInspection> inspectionClass, final LanguageLevel languageLevel) {
@@ -248,7 +248,7 @@ public class PythonInspectionsTest extends PyTestCase {
public void testInconsistentIndentation() {
doHighlightingTest(PyInconsistentIndentationInspection.class, LanguageLevel.PYTHON26);
}
-
+
public void testPyChainedComparisonsInspection() {
doHighlightingTest(PyChainedComparisonsInspection.class);
}
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
index fc8bf9acbbbb..33a3e270252d 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
@@ -73,6 +73,10 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase {
doTest();
}
+ public void testImportFunction() { // PY-1896
+ doTest();
+ }
+
public void testImportToContainingFile() { // PY-4372
myFixture.copyFileToProject("inspections/PyUnresolvedReferencesInspection/__init__.py", "PyUnresolvedReferencesInspection/__init__.py");
myFixture.copyFileToProject("inspections/PyUnresolvedReferencesInspection/importToContainingFile.py", "PyUnresolvedReferencesInspection/importToContainingFile.py");