diff --git a/python/psi-api/python-psi-api.iml b/python/psi-api/python-psi-api.iml
index 794de36364c4..c571537f090b 100644
--- a/python/psi-api/python-psi-api.iml
+++ b/python/psi-api/python-psi-api.iml
@@ -8,6 +8,7 @@
+
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyPsiFacade.java b/python/psi-api/src/com/jetbrains/python/psi/PyPsiFacade.java
new file mode 100644
index 000000000000..9ac9d08860b3
--- /dev/null
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyPsiFacade.java
@@ -0,0 +1,19 @@
+package com.jetbrains.python.psi;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.python.psi.impl.PyQualifiedName;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
+
+/**
+ * @author yole
+ */
+public abstract class PyPsiFacade {
+ public static PyPsiFacade getInstance(Project project) {
+ return ServiceManager.getService(project, PyPsiFacade.class);
+ }
+
+ public abstract QualifiedNameResolver qualifiedNameResolver(String qNameString);
+ public abstract QualifiedNameResolver qualifiedNameResolver(PyQualifiedName qualifiedName);
+
+}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java b/python/psi-api/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java
new file mode 100644
index 000000000000..79dcc9402eaf
--- /dev/null
+++ b/python/psi-api/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java
@@ -0,0 +1,41 @@
+package com.jetbrains.python.psi.resolve;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFileSystemItem;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * @author yole
+ */
+public interface QualifiedNameResolver {
+ QualifiedNameResolver fromElement(@NotNull PsiElement foothold);
+
+ QualifiedNameResolver fromModule(@NotNull Module module);
+
+ QualifiedNameResolver withAllModules();
+
+ QualifiedNameResolver withSdk(Sdk sdk);
+
+ QualifiedNameResolver withRelative(int relativeLevel);
+
+ QualifiedNameResolver withoutRoots();
+
+ QualifiedNameResolver withPlainDirectories();
+
+ @NotNull
+ List resultsAsList();
+
+ @Nullable
+ PsiFileSystemItem firstResult();
+
+ @NotNull
+ List resultsOfType(Class clazz);
+
+ @Nullable
+ T firstResultOfType(Class clazz);
+}
diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml
index cd196ba34e3a..248a20757180 100644
--- a/python/src/META-INF/python-plugin-common.xml
+++ b/python/src/META-INF/python-plugin-common.xml
@@ -412,6 +412,9 @@
+
+
diff --git a/python/src/com/jetbrains/pyqt/QtFileType.java b/python/src/com/jetbrains/pyqt/QtFileType.java
index f076e282cc09..3ac9da1d95b4 100644
--- a/python/src/com/jetbrains/pyqt/QtFileType.java
+++ b/python/src/com/jetbrains/pyqt/QtFileType.java
@@ -11,6 +11,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolverImpl;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -109,7 +110,7 @@ public abstract class QtFileType implements FileType, INativeFileType {
@Nullable
private static String findToolInPackage(String toolName, Module module, Sdk sdk, String name) {
- QualifiedNameResolver visitor = new QualifiedNameResolver(name).fromModule(module).withSdk(sdk);
+ QualifiedNameResolver visitor = new QualifiedNameResolverImpl(name).fromModule(module).withSdk(sdk);
List elements = visitor.resultsOfType(PsiDirectory.class);
for (PsiDirectory directory : elements) {
VirtualFile tool = directory.getVirtualFile().findChild(toolName + ".exe");
diff --git a/python/src/com/jetbrains/python/codeInsight/PyPsiPath.java b/python/src/com/jetbrains/python/codeInsight/PyPsiPath.java
index 5de11c35d74b..74fd57c05143 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyPsiPath.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyPsiPath.java
@@ -4,6 +4,7 @@ import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyQualifiedName;
import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolverImpl;
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
import org.jetbrains.annotations.Nullable;
@@ -24,7 +25,7 @@ public abstract class PyPsiPath {
@Nullable
@Override
public PsiElement resolve(PsiElement context) {
- QualifiedNameResolver visitor = new QualifiedNameResolver(myQualifiedName).fromElement(context);
+ QualifiedNameResolver visitor = new QualifiedNameResolverImpl(myQualifiedName).fromElement(context);
return visitor.firstResult();
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyPsiFacadeImpl.java b/python/src/com/jetbrains/python/psi/impl/PyPsiFacadeImpl.java
new file mode 100644
index 000000000000..036b4c820ade
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/impl/PyPsiFacadeImpl.java
@@ -0,0 +1,20 @@
+package com.jetbrains.python.psi.impl;
+
+import com.jetbrains.python.psi.PyPsiFacade;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolverImpl;
+
+/**
+ * @author yole
+ */
+public class PyPsiFacadeImpl extends PyPsiFacade {
+ @Override
+ public QualifiedNameResolver qualifiedNameResolver(String qNameString) {
+ return new QualifiedNameResolverImpl(qNameString);
+ }
+
+ @Override
+ public QualifiedNameResolver qualifiedNameResolver(PyQualifiedName qualifiedName) {
+ return new QualifiedNameResolverImpl(qualifiedName);
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java
index 64c6bcaae226..68546dad57e9 100644
--- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java
+++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java
@@ -17,10 +17,7 @@ import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyQualifiedName;
import com.jetbrains.python.psi.impl.PyReferenceExpressionImpl;
-import com.jetbrains.python.psi.resolve.PyResolveContext;
-import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
-import com.jetbrains.python.psi.resolve.RatedResolveResult;
-import com.jetbrains.python.psi.resolve.ResolveImportUtil;
+import com.jetbrains.python.psi.resolve.*;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
@@ -249,7 +246,7 @@ public class PyImportReference extends PyReferenceImpl {
}
private void fillFromQName(PyQualifiedName thisQName, InsertHandler insertHandler) {
- QualifiedNameResolver visitor = new QualifiedNameResolver(thisQName).fromElement(myCurrentFile);
+ QualifiedNameResolver visitor = new QualifiedNameResolverImpl(thisQName).fromElement(myCurrentFile);
for (PsiDirectory dir : visitor.resultsOfType(PsiDirectory.class)) {
fillFromDir(dir, insertHandler);
}
diff --git a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java
similarity index 96%
rename from python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java
rename to python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java
index 437017a5362c..f7dbc5af3c33 100644
--- a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolver.java
+++ b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java
@@ -28,7 +28,7 @@ import java.util.Set;
*
* @author yole
*/
-public class QualifiedNameResolver implements RootVisitor {
+public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameResolver {
boolean myCheckForPackage = true;
@Nullable private Module myModule;
private PsiFile myFootholdFile;
@@ -41,14 +41,15 @@ public class QualifiedNameResolver implements RootVisitor {
private boolean myWithoutRoots;
private Sdk myWithSdk;
- public QualifiedNameResolver(@NotNull String qNameString) {
+ public QualifiedNameResolverImpl(@NotNull String qNameString) {
myQualifiedName = PyQualifiedName.fromDottedString(qNameString);
}
- public QualifiedNameResolver(@NotNull PyQualifiedName qName) {
+ public QualifiedNameResolverImpl(@NotNull PyQualifiedName qName) {
myQualifiedName = qName;
}
+ @Override
public QualifiedNameResolver fromElement(@NotNull PsiElement foothold) {
if (foothold instanceof PsiDirectory) {
myFootholdFile = (PsiFile)PyUtil.turnDirIntoInit(foothold);
@@ -64,6 +65,7 @@ public class QualifiedNameResolver implements RootVisitor {
return this;
}
+ @Override
public QualifiedNameResolver fromModule(@NotNull Module module) {
setModule(module);
myPsiManager = PsiManager.getInstance(module.getProject());
@@ -77,6 +79,7 @@ public class QualifiedNameResolver implements RootVisitor {
}
}
+ @Override
public QualifiedNameResolver withAllModules() {
myVisitAllModules = true;
return this;
@@ -88,6 +91,7 @@ public class QualifiedNameResolver implements RootVisitor {
* @param sdk the SDK in which the name should be searched.
* @return this
*/
+ @Override
public QualifiedNameResolver withSdk(Sdk sdk) {
myWithSdk = sdk;
return this;
@@ -99,6 +103,7 @@ public class QualifiedNameResolver implements RootVisitor {
* @param relativeLevel if >= 0, we try to resolve at the specified number of levels above the current file.
* @return this
*/
+ @Override
public QualifiedNameResolver withRelative(int relativeLevel) {
myRelativeLevel = relativeLevel;
return this;
@@ -109,6 +114,7 @@ public class QualifiedNameResolver implements RootVisitor {
*
* @return this
*/
+ @Override
public QualifiedNameResolver withoutRoots() {
myWithoutRoots = true;
return this;
@@ -120,6 +126,7 @@ public class QualifiedNameResolver implements RootVisitor {
*
* @return
*/
+ @Override
public QualifiedNameResolver withPlainDirectories() {
myCheckForPackage = false;
return this;
@@ -144,6 +151,7 @@ public class QualifiedNameResolver implements RootVisitor {
return true;
}
+ @Override
@NotNull
public List resultsAsList() {
if (myFootholdFile != null && !myFootholdFile.isValid()) {
@@ -206,12 +214,14 @@ public class QualifiedNameResolver implements RootVisitor {
return resultList;
}
+ @Override
@Nullable
public PsiFileSystemItem firstResult() {
final List results = resultsAsList();
return results.size() > 0 ? results.get(0) : null;
}
+ @Override
@NotNull
public List resultsOfType(Class clazz) {
List result = new ArrayList();
@@ -224,6 +234,7 @@ public class QualifiedNameResolver implements RootVisitor {
return result;
}
+ @Override
@Nullable
public T firstResultOfType(Class clazz) {
final List list = resultsOfType(clazz);
diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java
index b5055d3a80e9..bd58f1d58655 100644
--- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java
+++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java
@@ -204,7 +204,7 @@ public class ResolveImportUtil {
}
try {
beingImported.add(marker);
- final QualifiedNameResolver visitor = new QualifiedNameResolver(qualifiedName).fromElement(sourceFile);
+ final QualifiedNameResolver visitor = new QualifiedNameResolverImpl(qualifiedName).fromElement(sourceFile);
if (relativeLevel > 0) {
// "from ...module import"
visitor.withRelative(relativeLevel).withoutRoots();
@@ -243,7 +243,7 @@ public class ResolveImportUtil {
final PyQualifiedName containingPath = findCanonicalImportPath(containingDirectory, null);
if (containingPath != null && containingPath.getComponentCount() > 0) {
final PyQualifiedName absolutePath = containingPath.append(qualifiedName.toString());
- final QualifiedNameResolver absoluteVisitor = new QualifiedNameResolver(absolutePath).fromElement(foothold);
+ final QualifiedNameResolver absoluteVisitor = new QualifiedNameResolverImpl(absolutePath).fromElement(foothold);
return absoluteVisitor.resultsAsList();
}
}
@@ -253,7 +253,7 @@ public class ResolveImportUtil {
@Nullable
public static PsiElement resolveModuleInRoots(@NotNull PyQualifiedName moduleQualifiedName, @Nullable PsiElement foothold) {
if (foothold == null) return null;
- QualifiedNameResolver visitor = new QualifiedNameResolver(moduleQualifiedName).fromElement(foothold);
+ QualifiedNameResolver visitor = new QualifiedNameResolverImpl(moduleQualifiedName).fromElement(foothold);
return visitor.firstResult();
}