@NotNull private static List<RatedResolveResult> resolveInDirectory( @NotNull final String referencedName, @Nullable final PsiFile containingFile, final PsiDirectory dir, boolean isFileOnly, boolean checkForPackage) { final PsiDirectory subdir = dir.findSubdirectory(referencedName); if (subdir != null && (!checkForPackage || PyUtil.isPackage(subdir, containingFile))) { return ResolveResultList.to(subdir); } final PsiFile module = findPyFileInDir(dir, referencedName); if (module != null) { return ResolveResultList.to(module); } if (!isFileOnly) { // not a subdir, not a file; could be a name in parent/__init__.py final PsiFile initPy = dir.findFile(PyNames.INIT_DOT_PY); if (initPy == containingFile) { return Collections.emptyList(); // don't dive into the file we're in } if (initPy instanceof PyFile) { return ((PyFile) initPy).multiResolveName(referencedName); } } return Collections.emptyList(); }
@NotNull private static List<RatedResolveResult> 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 List<RatedResolveResult> resolved = resolveInDirectory( referencedName, containingFile, (PsiDirectory) parentDir, fileOnly, checkForPackage); if (!resolved.isEmpty()) { for (RatedResolveResult result : resolved) { if (result.getRate() > RatedResolveResult.RATE_LOW) { return resolved; } } } if (parent instanceof PsiFile) { final PsiElement foreign = resolveForeignImports((PsiFile) parent, referencedName); if (foreign != null) { final ResolveResultList results = new ResolveResultList(); results.addAll(resolved); results.poke(foreign, RatedResolveResult.RATE_NORMAL); return results; } } return resolved; } return Collections.emptyList(); }
@NotNull private static List<RatedResolveResult> resolveInPackageModule( @NotNull PyFile parent, @NotNull String referencedName, @Nullable PsiFile containingFile, boolean fileOnly, boolean checkForPackage) { final List<RatedResolveResult> moduleMembers = resolveModuleMember(parent, referencedName); final List<RatedResolveResult> resolvedInModule = Lists.newArrayList(); final List<RatedResolveResult> results = Lists.newArrayList(); for (RatedResolveResult member : moduleMembers) { final PsiElement moduleMember = member.getElement(); if (!fileOnly || PyUtil.instanceOf(moduleMember, PsiFile.class, PsiDirectory.class)) { results.add(member); if (moduleMember != null && !preferResolveInDirectoryOverModule(moduleMember)) { resolvedInModule.add(member); } } } if (!resolvedInModule.isEmpty()) { return resolvedInModule; } final List<RatedResolveResult> resolvedInDirectory = resolveInPackageDirectory( parent, referencedName, containingFile, fileOnly, checkForPackage); if (!resolvedInDirectory.isEmpty()) { return resolvedInDirectory; } return results; }
/** * Resolves a module reference in a general case. * * @param qualifiedName qualified name of the module reference to resolve * @param sourceFile where that reference resides; serves as PSI foothold to determine module, * project, etc. * @param importIsAbsolute if false, try old python 2.x's "relative first, absolute next" * approach. * @param relativeLevel if > 0, step back from sourceFile and resolve from there (even if * importIsAbsolute is false!). * @return list of possible candidates */ @NotNull public static List<PsiElement> resolveModule( @Nullable QualifiedName qualifiedName, @Nullable PsiFile sourceFile, boolean importIsAbsolute, int relativeLevel) { if (qualifiedName == null || sourceFile == null) { return Collections.emptyList(); } final ResolveModuleParams params = new ResolveModuleParams(qualifiedName, sourceFile, importIsAbsolute, relativeLevel); return PyUtil.getParameterizedCachedValue( sourceFile, params, ResolveImportUtil::calculateResolveModule); }
/** * Finds a directory that many levels above a given file, making sure that every level has an * __init__.py. * * @param base file that works as a reference. * @param depth must be positive, 1 means the dir that contains base, 2 is one dir above, etc. * @return found directory, or null. */ @Nullable public static PsiDirectory stepBackFrom(PsiFile base, int depth) { if (depth == 0) { return base.getContainingDirectory(); } PsiDirectory result; if (base != null) { base = base.getOriginalFile(); // just to make sure result = base.getContainingDirectory(); int count = 1; while (result != null && PyUtil.isPackage(result, base)) { if (count >= depth) return result; result = result.getParentDirectory(); count += 1; } } return null; }
public static ResolveResultList rateResults(List<? extends PsiElement> targets) { ResolveResultList ret = new ResolveResultList(); for (PsiElement target : targets) { if (target instanceof PsiDirectory) { target = PyUtil.getPackageElement((PsiDirectory) target, null); } if (target != null) { int rate = RatedResolveResult.RATE_HIGH; if (target instanceof PyFile) { for (PyResolveResultRater rater : Extensions.getExtensions(PyResolveResultRater.EP_NAME)) { rate += rater.getImportElementRate(target); } } else if (isDunderAll(target)) { rate = RatedResolveResult.RATE_NORMAL; } ret.poke(target, rate); } } return ret; }
@NotNull public static List<RatedResolveResult> resolveNameInFromImport( PyFromImportStatement importStatement, @NotNull QualifiedName qName) { PsiFile file = importStatement.getContainingFile().getOriginalFile(); String name = qName.getComponents().get(0); final List<PsiElement> candidates = importStatement.resolveImportSourceCandidates(); List<PsiElement> resultList = new ArrayList<PsiElement>(); for (PsiElement candidate : candidates) { if (!candidate.isValid()) { throw new PsiInvalidElementAccessException( candidate, "Got an invalid candidate from resolveImportSourceCandidates(): " + candidate.getClass()); } if (candidate instanceof PsiDirectory) { candidate = PyUtil.getPackageElement((PsiDirectory) candidate, importStatement); } List<RatedResolveResult> results = resolveChildren(candidate, name, file, false, true); if (!results.isEmpty()) { for (RatedResolveResult result : results) { final PsiElement element = result.getElement(); if (element != null) { if (!element.isValid()) { throw new PsiInvalidElementAccessException( element, "Got an invalid candidate from resolveChild(): " + element.getClass()); } resultList.add(element); } } } } if (!resultList.isEmpty()) { return rateResults(resultList); } return Collections.emptyList(); }
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); }