mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-26062, PY-38540, PY-25935: Various Django performance improvements.
* Do not provide references for "open" in Django (already done by another code) * Do not use full resolve for class and functions names. In most cases "resolve", "ManyToMany" and "ModelForm" are imported as-is, not with aliases. GitOrigin-RevId: 8a0803e6b19482654c91186aa9754ea3d91da282
This commit is contained in:
committed by
intellij-monorepo-bot
parent
388d7bf175
commit
f8544fb8ee
@@ -21,12 +21,14 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiCacheKey;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
@@ -72,9 +74,22 @@ public final class NameResolverTools {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #isName(PyElement, FQNamesProvider...)} for named elements, but only checks name.
|
||||
* Aliases not supported, but much lighter that way
|
||||
*/
|
||||
public static boolean isNameShortCut(@NotNull PyElement element, @NotNull FQNamesProvider... namesProviders) {
|
||||
String name = element.getName();
|
||||
if (name == null) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.stream(namesProviders).anyMatch(o -> getLastComponents(o).contains(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if FQ element name is one of provided names. May be <strong>heavy</strong>.
|
||||
* It is always better to use less accurate but lighter {@link #isCalleeShortCut(PyCallExpression, FQNamesProvider)}
|
||||
* and {@link #isNameShortCut(PyElement, FQNamesProvider...)}
|
||||
*
|
||||
* @param element element to check
|
||||
* @param namesProviders some enum that has one or more names
|
||||
@@ -83,7 +98,8 @@ public final class NameResolverTools {
|
||||
public static boolean isName(@NotNull final PyElement element, @NotNull final FQNamesProvider... namesProviders) {
|
||||
assert element.isValid();
|
||||
final Pair<String, String> qualifiedAndClassName = RecursionManager.doPreventingRecursion(element, false,
|
||||
() -> QUALIFIED_AND_CLASS_NAME.getValue(element));
|
||||
() -> QUALIFIED_AND_CLASS_NAME
|
||||
.getValue(element));
|
||||
LOG.assertTrue(qualifiedAndClassName != null);
|
||||
//noinspection ConstantConditions
|
||||
if (qualifiedAndClassName == null) return false;
|
||||
@@ -119,7 +135,7 @@ public final class NameResolverTools {
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #isName(PyElement, FQNamesProvider...)} for call expr, but first checks name.
|
||||
* Same as {@link #isName(PyElement, FQNamesProvider...)} for call expr, but only checks name.
|
||||
* Aliases not supported, but much lighter that way
|
||||
*
|
||||
* @param call expr
|
||||
@@ -127,7 +143,7 @@ public final class NameResolverTools {
|
||||
* @return true if callee is correct
|
||||
*/
|
||||
public static boolean isCalleeShortCut(@NotNull final PyCallExpression call,
|
||||
@NotNull final FQNamesProvider function) {
|
||||
@NotNull final FQNamesProvider... function) {
|
||||
final PyExpression callee = call.getCallee();
|
||||
if (callee == null) {
|
||||
return false;
|
||||
@@ -135,8 +151,7 @@ public final class NameResolverTools {
|
||||
|
||||
final String callableName = callee.getName();
|
||||
|
||||
final Collection<String> possibleNames = getLastComponents(function);
|
||||
return possibleNames.contains(callableName) && call.isCallee(function);
|
||||
return Arrays.stream(function).anyMatch(o -> getLastComponents(o).contains(callableName));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -178,6 +193,7 @@ public final class NameResolverTools {
|
||||
|
||||
/**
|
||||
* Check if class has parent with some name
|
||||
*
|
||||
* @param child class to check
|
||||
*/
|
||||
public static boolean isSubclass(@NotNull final PyClass child,
|
||||
@@ -205,7 +221,8 @@ public final class NameResolverTools {
|
||||
@Override
|
||||
public boolean value(final PsiElement element) {
|
||||
if (element instanceof PyCallExpression) {
|
||||
return ((PyCallExpression)element).isCallee(myNameToSearch);
|
||||
PyCallExpression callExpression = (PyCallExpression)element;
|
||||
return isCalleeShortCut(callExpression, myNameToSearch);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -233,14 +233,17 @@ public interface PyCallExpression extends PyCallSiteExpression {
|
||||
|
||||
/**
|
||||
* Checks if the qualified name of the callee matches any of the specified names provided by provider.
|
||||
* May be <strong>heavy</strong>.
|
||||
* Use {@link NameResolverTools#isCalleeShortCut(PyCallExpression, FQNamesProvider)}
|
||||
* if you can.
|
||||
* May be <strong>heavy</strong>, and it is not recommended to use.
|
||||
* Use {@link NameResolverTools#isCalleeShortCut(PyCallExpression, FQNamesProvider...)} or
|
||||
* {@link com.jetbrains.extensions.python.PyCallExpressionExtKt#isCalleeName(PyCallExpression, FQNamesProvider...)}.
|
||||
*
|
||||
* @param name providers that provides one or more names to check
|
||||
* @return true if matches, false otherwise
|
||||
* @see com.jetbrains.python.nameResolver
|
||||
* @see com.jetbrains.extensions.python.PyCallExpressionExtKt#isCalleeName(PyCallExpression, FQNamesProvider...)
|
||||
* @deprecated use {@link com.jetbrains.extensions.python.PyCallExpressionExtKt#isCalleeName(PyCallExpression, FQNamesProvider...)}.
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean isCallee(@NotNull FQNamesProvider... name) {
|
||||
final PyExpression callee = getCallee();
|
||||
return callee instanceof PyReferenceExpression && NameResolverTools.isName(callee, name);
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.PythonFQDNNames;
|
||||
import com.jetbrains.python.nameResolver.NameResolverTools;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -302,7 +303,7 @@ public class PyEvaluator {
|
||||
}
|
||||
|
||||
// Support dict([("k", "v")]) syntax
|
||||
if (myEnableResolve && expression.isCallee(PythonFQDNNames.DICT_CLASS)) {
|
||||
if (myEnableResolve && NameResolverTools.isCalleeShortCut(expression, PythonFQDNNames.DICT_CLASS)) {
|
||||
final Collection<PyTupleExpression> tuples = PsiTreeUtil.findChildrenOfType(expression, PyTupleExpression.class);
|
||||
if (!tuples.isEmpty()) {
|
||||
final Map<Object, Object> result = new HashMap<>();
|
||||
@@ -470,7 +471,7 @@ public class PyEvaluator {
|
||||
@Nullable
|
||||
private Object evaluateOrGet(@Nullable final PyExpression expression) {
|
||||
final Object result = evaluate(expression);
|
||||
if (result !=null) {
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return myAllowExpressionsAsValues ? expression : null;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.extensions.python
|
||||
|
||||
import com.jetbrains.python.nameResolver.FQNamesProvider
|
||||
import com.jetbrains.python.nameResolver.NameResolverTools
|
||||
import com.jetbrains.python.psi.PyAssignmentStatement
|
||||
import com.jetbrains.python.psi.PyCallExpression
|
||||
import com.jetbrains.python.psi.PyPossibleClassMember
|
||||
|
||||
/**
|
||||
* Checks if ``foo = SomeExpr()`` where foo is class attribute
|
||||
*/
|
||||
val PyCallExpression.isClassAttribute: Boolean
|
||||
get() =
|
||||
(parent as? PyAssignmentStatement)?.targets?.filterIsInstance<PyPossibleClassMember>()?.any { it.containingClass != null } == true
|
||||
|
||||
/**
|
||||
* Checks if callee has certain name. Only name is checked, so import aliases aren't supported, but it works pretty fast
|
||||
*/
|
||||
fun PyCallExpression.isCalleeName(vararg names: FQNamesProvider): Boolean = NameResolverTools.isCalleeShortCut(this, *names)
|
||||
|
||||
Reference in New Issue
Block a user