diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 3c5c1b1ee3ce..3e368553c1fa 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -846,20 +846,19 @@ public class PyUtil { }); } - public static T getParameterizedCachedValue(@NotNull PsiElement element, @NotNull P param, @NotNull NotNullFunction f) { - final Map cache = CachedValuesManager.getCachedValue(element, new CachedValueProvider>() { + private static final Object NULL_VALUE = new Object(); + public static T getParameterizedCachedValue(@NotNull PsiElement element, @Nullable P param, @NotNull NullableFunction f) { + final Map cache = CachedValuesManager.getCachedValue(element, new CachedValueProvider>() { @Nullable @Override - public Result> compute() { + public Result> compute() { + // TODO should be concurrent map instead return Result.create(Maps.newHashMap(), PsiModificationTracker.MODIFICATION_COUNT); } }); - T result = cache.get(param); - if (result == null) { - result = f.fun(param); - cache.put(param, result); - } - return result; + final Object wrapped = cache.computeIfAbsent(param, p -> ObjectUtils.notNull(f.fun(param), NULL_VALUE)); + //noinspection unchecked + return (T)ObjectUtils.nullizeByCondition(wrapped, NULL_VALUE::equals); } /** diff --git a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java index bab8681fbbd6..1baebc144899 100644 --- a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java +++ b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameFinder.java @@ -27,10 +27,7 @@ import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.PyElement; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -114,49 +111,51 @@ public class QualifiedNameFinder { */ @Nullable public static QualifiedName findCanonicalImportPath(@NotNull PsiElement symbol, @Nullable PsiElement foothold) { - PsiFileSystemItem srcfile = symbol instanceof PsiFileSystemItem ? (PsiFileSystemItem)symbol : symbol.getContainingFile(); - if (srcfile == null) { - return null; - } - VirtualFile virtualFile = srcfile.getVirtualFile(); - if (virtualFile == null) { - return null; - } - if (srcfile instanceof PsiFile && symbol instanceof PsiNamedElement && !(symbol instanceof PsiFileSystemItem)) { - PsiElement toplevel = symbol; - if (symbol instanceof PyFunction) { - final PyClass containingClass = ((PyFunction)symbol).getContainingClass(); - if (containingClass != null) { - toplevel = containingClass; - } + return PyUtil.getParameterizedCachedValue(symbol, foothold, param -> { + PsiFileSystemItem srcfile = symbol instanceof PsiFileSystemItem ? (PsiFileSystemItem)symbol : symbol.getContainingFile(); + if (srcfile == null) { + return null; } - PsiDirectory dir = ((PsiFile)srcfile).getContainingDirectory(); - while (dir != null) { - PsiFile initPy = dir.findFile(PyNames.INIT_DOT_PY); - if (initPy == null) { - break; - } - if (initPy instanceof PyFile) { - //noinspection ConstantConditions - final List resolved = ((PyFile)initPy).multiResolveName(((PsiNamedElement)toplevel).getName()); - final PsiElement finalTopLevel = toplevel; - if (resolved.stream().anyMatch(r -> r.getElement() == finalTopLevel)) { - virtualFile = dir.getVirtualFile(); + VirtualFile virtualFile = srcfile.getVirtualFile(); + if (virtualFile == null) { + return null; + } + if (srcfile instanceof PsiFile && symbol instanceof PsiNamedElement && !(symbol instanceof PsiFileSystemItem)) { + PsiElement toplevel = symbol; + if (symbol instanceof PyFunction) { + final PyClass containingClass = ((PyFunction)symbol).getContainingClass(); + if (containingClass != null) { + toplevel = containingClass; } } - dir = dir.getParentDirectory(); - } - } - final QualifiedName qname = findShortestImportableQName(foothold != null ? foothold : symbol, virtualFile); - if (qname != null) { - for (PyCanonicalPathProvider provider : Extensions.getExtensions(PyCanonicalPathProvider.EP_NAME)) { - final QualifiedName restored = provider.getCanonicalPath(qname, foothold); - if (restored != null) { - return restored; + PsiDirectory dir = ((PsiFile)srcfile).getContainingDirectory(); + while (dir != null) { + PsiFile initPy = dir.findFile(PyNames.INIT_DOT_PY); + if (initPy == null) { + break; + } + if (initPy instanceof PyFile) { + //noinspection ConstantConditions + final List resolved = ((PyFile)initPy).multiResolveName(((PsiNamedElement)toplevel).getName()); + final PsiElement finalTopLevel = toplevel; + if (resolved.stream().anyMatch(r -> r.getElement() == finalTopLevel)) { + virtualFile = dir.getVirtualFile(); + } + } + dir = dir.getParentDirectory(); } } - } - return qname; + final QualifiedName qname = findShortestImportableQName(param != null ? param : symbol, virtualFile); + if (qname != null) { + for (PyCanonicalPathProvider provider : Extensions.getExtensions(PyCanonicalPathProvider.EP_NAME)) { + final QualifiedName restored = provider.getCanonicalPath(qname, param); + if (restored != null) { + return restored; + } + } + } + return qname; + }); } @Nullable