Extracted several logically independent parts from resolveChild()
authorAndrey Vlasovskikh <andrey.vlasovskikh@jetbrains.com>
Wed, 1 Jul 2015 17:10:53 +0000 (20:10 +0300)
committerAndrey Vlasovskikh <andrey.vlasovskikh@jetbrains.com>
Wed, 1 Jul 2015 17:50:39 +0000 (20:50 +0300)
python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java

index b156b608c6bbcf95539debec9e8ea860aa34c50b..5475aa96989624a536b1be2ffcacca352173e350 100644 (file)
@@ -269,56 +269,83 @@ public class ResolveImportUtil {
   @Nullable
   public static PsiElement resolveChild(@Nullable final PsiElement parent, @NotNull final String referencedName,
                                         @Nullable final PsiFile containingFile, boolean fileOnly, boolean checkForPackage) {
-    PsiDirectory dir = null;
-    PsiElement resultElement = null;
-    final PyResolveContext resolveContext = PyResolveContext.defaultContext();
-    if (parent instanceof PyFileImpl) {
-      PsiElement possibleResult = null;
-      if (PyNames.INIT_DOT_PY.equals(((PyFile)parent).getName())) {
-        dir = ((PyFile)parent).getContainingDirectory();
-        possibleResult = resolveInDirectory(referencedName, containingFile, dir, fileOnly, checkForPackage);
-      }
-
-      final PyModuleType moduleType = new PyModuleType((PyFile)parent);
-      final List<? extends RatedResolveResult> results = moduleType.resolveMember(referencedName, null, AccessDirection.READ,
-                                                                                  resolveContext);
-      final PsiElement moduleMember = results != null && !results.isEmpty() ? results.get(0).getElement() : null;
-      if (!fileOnly || PyUtil.instanceOf(moduleMember, PsiFile.class, PsiDirectory.class)) {
-        resultElement = moduleMember;
-      }
-      if (resultElement != null && !PyUtil.instanceOf(resultElement, PsiFile.class, PsiDirectory.class) &&
-          PsiTreeUtil.getStubOrPsiParentOfType(resultElement, PyExceptPart.class) == null && !isDunderAll(resultElement)) {
-        return resultElement;
-      }
-
-      if (possibleResult != null) return possibleResult;
-
-      if (resultElement != null) {
-        return resultElement;
-      }
+    if (parent == null) {
+      return null;
+    }
+    else if (parent instanceof PyFile) {
+      return resolveInPackageModule((PyFile)parent, referencedName, containingFile, fileOnly, checkForPackage);
     }
     else if (parent instanceof PsiDirectory) {
-      dir = (PsiDirectory)parent;
+      return resolveInPackageDirectory(parent, referencedName, containingFile, fileOnly, checkForPackage);
     }
-    else if (parent != null) {
-      PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, resolveContext.getTypeEvalContext(), null);
-      if (refType != null) {
-        final List<? extends RatedResolveResult> result = refType.resolveMember(referencedName, null, AccessDirection.READ, resolveContext);
-        if (result != null && !result.isEmpty()) {
-          return result.get(0).getElement();
-        }
-      }
+    else {
+      return resolveMemberFromReferenceTypeProviders(parent, referencedName);
     }
-    if (dir != null) {
-      final PsiElement result = resolveInDirectory(referencedName, containingFile, dir, fileOnly, checkForPackage);
-      if (result != null) {
-        return result;
+  }
+
+  @Nullable
+  private static PsiElement resolveInPackageModule(@NotNull PyFile parent, @NotNull String referencedName,
+                                                   @Nullable PsiFile containingFile, boolean fileOnly, boolean checkForPackage) {
+    final PsiElement moduleMember = resolveModuleMember(parent, referencedName);
+    final PsiElement resolved = !fileOnly || PyUtil.instanceOf(moduleMember, PsiFile.class, PsiDirectory.class) ?
+                                moduleMember : null;
+    if (resolved != null && !preferResolveInDirectoryOverModule(resolved)) {
+      return resolved;
+    }
+
+    final PsiElement resolvedInDirectory = resolveInPackageDirectory(parent, referencedName, containingFile, fileOnly, checkForPackage);
+    if (resolvedInDirectory != null) {
+      return resolvedInDirectory;
+    }
+
+    return resolved;
+  }
+
+  private static boolean preferResolveInDirectoryOverModule(@NotNull PsiElement resolved) {
+    return PsiTreeUtil.getStubOrPsiParentOfType(resolved, PyExceptPart.class) != null ||
+           PyUtil.instanceOf(resolved, PsiFile.class, PsiDirectory.class) ||  // XXX: Workaround for PY-9439
+           isDunderAll(resolved);
+  }
+
+  @Nullable
+  private static PsiElement resolveModuleMember(@NotNull PyFile file, @NotNull String referencedName) {
+    final PyModuleType moduleType = new PyModuleType(file);
+    final PyResolveContext resolveContext = PyResolveContext.defaultContext();
+    final List<? extends RatedResolveResult> results = moduleType.resolveMember(referencedName, null, AccessDirection.READ,
+                                                                                resolveContext);
+    return results != null && !results.isEmpty() ? results.get(0).getElement() : null;
+  }
+
+  @Nullable
+  private static PsiElement resolveInPackageDirectory(@Nullable PsiElement parent, @NotNull String referencedName,
+                                                      @Nullable PsiFile containingFile, boolean fileOnly,
+                                                      boolean checkForPackage) {
+    final PsiElement parentDir = PyUtil.turnInitIntoDir(parent);
+    if (parentDir instanceof PsiDirectory) {
+      final PsiElement resolved = resolveInDirectory(referencedName, containingFile, (PsiDirectory)parentDir, fileOnly, checkForPackage);
+      if (resolved != null) {
+        return resolved;
       }
       if (parent instanceof PsiFile) {
-        final PsiElement element = new QualifiedNameResolverImpl(referencedName).fromElement(parent).withoutRoots().firstResult();
-        if (element != null) {
-          return element;
-        }
+        return resolveForeignImports((PsiFile)parent, referencedName);
+      }
+    }
+    return null;
+  }
+
+  @Nullable
+  private static PsiElement resolveForeignImports(@NotNull PsiFile foothold, @NotNull String referencedName) {
+    return new QualifiedNameResolverImpl(referencedName).fromElement(foothold).withoutRoots().firstResult();
+  }
+
+  @Nullable
+  private static PsiElement resolveMemberFromReferenceTypeProviders(@NotNull PsiElement parent, @NotNull String referencedName) {
+    final PyResolveContext resolveContext = PyResolveContext.defaultContext();
+    PyType refType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(parent, resolveContext.getTypeEvalContext(), null);
+    if (refType != null) {
+      final List<? extends RatedResolveResult> result = refType.resolveMember(referencedName, null, AccessDirection.READ, resolveContext);
+      if (result != null && !result.isEmpty()) {
+        return result.get(0).getElement();
       }
     }
     return null;