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(); }