mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-85271 Reformat files with incorrect formatting
GitOrigin-RevId: 6c8ee5d2ca5f5807c6534e8a97843d16371562d8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c1e6f78373
commit
d7e26c8bc1
@@ -17,7 +17,7 @@ public enum PythonFunctionParameters implements FunctionParameter {
|
||||
/**
|
||||
* environment.setdevault(key, failobj) # failobj
|
||||
*/
|
||||
ENV_SET_DEFAULT_FAILOBJ("failobj",1);
|
||||
ENV_SET_DEFAULT_FAILOBJ("failobj", 1);
|
||||
|
||||
|
||||
private final @Nullable String myName;
|
||||
|
||||
@@ -216,7 +216,8 @@ public class PyCustomMember extends UserDataHolderBase {
|
||||
targetClass = (PyClass)resolveTarget;
|
||||
}
|
||||
|
||||
return PyCustomMemberProvider.getInstance().createPyCustomMemberTarget(this, targetClass, context, resolveTarget, myTypeCallback, myCustomTypeInfo, myResolveToInstance);
|
||||
return PyCustomMemberProvider.getInstance()
|
||||
.createPyCustomMemberTarget(this, targetClass, context, resolveTarget, myTypeCallback, myCustomTypeInfo, myResolveToInstance);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -284,5 +285,4 @@ public class PyCustomMember extends UserDataHolderBase {
|
||||
myCustomTypeInfo = customInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public abstract class PyPsiPath {
|
||||
return null;
|
||||
}
|
||||
if (parent instanceof PyFile) {
|
||||
return ((PyFile) parent).findTopLevelClass(myClassName);
|
||||
return ((PyFile)parent).findTopLevelClass(myClassName);
|
||||
}
|
||||
if (resolveContext.getTypeEvalContext().maySwitchToAST(parent)) {
|
||||
if (parent instanceof PyClass) {
|
||||
@@ -115,10 +115,10 @@ public abstract class PyPsiPath {
|
||||
return null;
|
||||
}
|
||||
if (parent instanceof PyFile) {
|
||||
return ((PyFile) parent).findTopLevelFunction(myFunctionName);
|
||||
return ((PyFile)parent).findTopLevelFunction(myFunctionName);
|
||||
}
|
||||
if (parent instanceof PyClass) {
|
||||
return ((PyClass) parent).findMethodByName(myFunctionName, false, resolveContext.getTypeEvalContext());
|
||||
return ((PyClass)parent).findMethodByName(myFunctionName, false, resolveContext.getTypeEvalContext());
|
||||
}
|
||||
if (resolveContext.getTypeEvalContext().maySwitchToAST(parent)) {
|
||||
for (PsiElement element : parent.getChildren()) {
|
||||
@@ -230,14 +230,14 @@ public abstract class PyPsiPath {
|
||||
|
||||
final PyExpression callee = node.getCallee();
|
||||
if (callee instanceof PyReferenceExpression) {
|
||||
final String calleeName = ((PyReferenceExpression) callee).getReferencedName();
|
||||
final String calleeName = ((PyReferenceExpression)callee).getReferencedName();
|
||||
if (myCallName.equals(calleeName)) {
|
||||
final PyExpression[] args = node.getArguments();
|
||||
if (myArgs.length <= args.length) {
|
||||
boolean argsMatch = true;
|
||||
for (int i = 0; i < myArgs.length; i++) {
|
||||
if (!(args[i] instanceof PyStringLiteralExpression) ||
|
||||
!myArgs [i].equals(((PyStringLiteralExpression)args[i]).getStringValue())) {
|
||||
!myArgs[i].equals(((PyStringLiteralExpression)args[i]).getStringValue())) {
|
||||
argsMatch = false;
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-1
@@ -58,6 +58,7 @@ public abstract class PyInspectionExtension {
|
||||
|
||||
/**
|
||||
* Enable "unresolved reference" inspection regardless of IDE type and initialized SDK.
|
||||
*
|
||||
* @return true -- Enable forcibly, false -- disable forcibly, null -- act as usual.
|
||||
*/
|
||||
public Boolean overrideUnresolvedReferenceInspection(@NotNull PsiFile file) {
|
||||
@@ -124,5 +125,5 @@ public abstract class PyInspectionExtension {
|
||||
/**
|
||||
* @return Do not report "unused import"
|
||||
*/
|
||||
public boolean ignoreUnusedImports(@NotNull PyImportedNameDefiner importNameDefiner) {return false;}
|
||||
public boolean ignoreUnusedImports(@NotNull PyImportedNameDefiner importNameDefiner) { return false; }
|
||||
}
|
||||
|
||||
@@ -109,7 +109,8 @@ public final class NameResolverTools {
|
||||
* @param functionName function to find
|
||||
* @return parent call or null if not found
|
||||
*/
|
||||
public static @Nullable PyCallExpression findCallExpParent(final @NotNull PsiElement anchor, final @NotNull FQNamesProvider functionName) {
|
||||
public static @Nullable PyCallExpression findCallExpParent(final @NotNull PsiElement anchor,
|
||||
final @NotNull FQNamesProvider functionName) {
|
||||
final PsiElement parent = PsiTreeUtil.findFirstParent(anchor, new MyFunctionCondition(functionName));
|
||||
if (parent instanceof PyCallExpression) {
|
||||
return (PyCallExpression)parent;
|
||||
@@ -151,7 +152,7 @@ public final class NameResolverTools {
|
||||
/**
|
||||
* Checks if some string contains last component one of name
|
||||
*
|
||||
* @param text test to check
|
||||
* @param text test to check
|
||||
*/
|
||||
public static boolean isContainsName(final @NotNull String text, final @NotNull FQNamesProvider names) {
|
||||
for (final String lastComponent : getLastComponents(names)) {
|
||||
@@ -165,7 +166,7 @@ public final class NameResolverTools {
|
||||
/**
|
||||
* Checks if some file contains last component one of name
|
||||
*
|
||||
* @param file file to check
|
||||
* @param file file to check
|
||||
*/
|
||||
public static boolean isContainsName(final @NotNull PsiFile file, final @NotNull FQNamesProvider names) {
|
||||
return isContainsName(file.getText(), names);
|
||||
|
||||
@@ -24,5 +24,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
public interface PsiReferenceEx extends PsiReference {
|
||||
@Nullable
|
||||
HighlightSeverity getUnresolvedHighlightSeverity(TypeEvalContext context);
|
||||
@Nullable @Nls String getUnresolvedDescription();
|
||||
|
||||
@Nullable
|
||||
@Nls
|
||||
String getUnresolvedDescription();
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ public interface PyAssignmentStatement extends PyAstAssignmentStatement, PyState
|
||||
* <br/>
|
||||
* If RHS and LHS are mis-balanced, certain target or value expressions may be null.
|
||||
* If source is severely incorrect, the returned mapping is empty.
|
||||
*
|
||||
* @return a list of [target, value] pairs; either part of a pair may be null, but not both.
|
||||
*/
|
||||
@Override
|
||||
@@ -77,5 +78,4 @@ public interface PyAssignmentStatement extends PyAstAssignmentStatement, PyState
|
||||
default @Nullable PyExpression getLeftHandSideExpression() {
|
||||
return (PyExpression)PyAstAssignmentStatement.super.getLeftHandSideExpression();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,9 +25,10 @@ import java.util.Map;
|
||||
/**
|
||||
* Represents a class declaration in source.
|
||||
*/
|
||||
public interface PyClass extends PyAstClass, PsiNameIdentifierOwner, PyCompoundStatement, PyDocStringOwner, StubBasedPsiElement<PyClassStub>,
|
||||
ScopeOwner, PyDecoratable, PyTypedElement, PyQualifiedNameOwner, PyStatementListContainer, PyWithAncestors,
|
||||
PyTypeParameterListOwner, PyDeprecatable {
|
||||
public interface PyClass
|
||||
extends PyAstClass, PsiNameIdentifierOwner, PyCompoundStatement, PyDocStringOwner, StubBasedPsiElement<PyClassStub>,
|
||||
ScopeOwner, PyDecoratable, PyTypedElement, PyQualifiedNameOwner, PyStatementListContainer, PyWithAncestors,
|
||||
PyTypeParameterListOwner, PyDeprecatable {
|
||||
PyClass[] EMPTY_ARRAY = new PyClass[0];
|
||||
ArrayFactory<PyClass> ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new PyClass[count];
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.Set;
|
||||
public interface PyClassPattern extends PyAstClassPattern, PyPattern {
|
||||
Set<String> SPECIAL_BUILTINS = Set.of(
|
||||
"bool", "bytearray", "bytes", "dict", "float", "frozenset", "int", "list", "set", "str", "tuple");
|
||||
|
||||
|
||||
@Override
|
||||
default @NotNull PyReferenceExpression getClassNameReference() {
|
||||
return (PyReferenceExpression)PyAstClassPattern.super.getClassNameReference();
|
||||
|
||||
@@ -23,5 +23,4 @@ public interface PyElement extends PyAstElement {
|
||||
* An empty array to return cheaply without allocating it anew.
|
||||
*/
|
||||
PyElement[] EMPTY_ARRAY = new PyElement[0];
|
||||
|
||||
}
|
||||
|
||||
@@ -30,15 +30,15 @@ public abstract class PyElementGenerator extends PyAstElementGenerator {
|
||||
/**
|
||||
* Creates a string literal, adding appropriate quotes, properly escaping characters inside.
|
||||
*
|
||||
* @param destination where the literal is destined to; used to determine the encoding.
|
||||
* @param unescaped the string
|
||||
* @param preferUTF8 try to use UTF8 (would use ascii if false)
|
||||
* @param destination where the literal is destined to; used to determine the encoding.
|
||||
* @param unescaped the string
|
||||
* @param preferUTF8 try to use UTF8 (would use ascii if false)
|
||||
* @param preferDoubleQuotes try to use double/single quotes
|
||||
* @return a newly created literal
|
||||
*/
|
||||
protected abstract PyStringLiteralExpression createStringLiteralFromString(@Nullable PsiFile destination,
|
||||
@NotNull String unescaped,
|
||||
boolean preferUTF8, boolean preferDoubleQuotes);
|
||||
@NotNull String unescaped,
|
||||
boolean preferUTF8, boolean preferDoubleQuotes);
|
||||
|
||||
public abstract PyStringLiteralExpression createStringLiteralFromString(@NotNull String unescaped, boolean preferDoubleQuotes);
|
||||
|
||||
@@ -55,11 +55,13 @@ public abstract class PyElementGenerator extends PyAstElementGenerator {
|
||||
@NotNull PyExpression rightOperand);
|
||||
|
||||
@Override
|
||||
public @NotNull PyExpression createExpressionFromText(@NotNull LanguageLevel languageLevel, @NotNull String text) throws IncorrectOperationException {
|
||||
public @NotNull PyExpression createExpressionFromText(@NotNull LanguageLevel languageLevel, @NotNull String text)
|
||||
throws IncorrectOperationException {
|
||||
return (PyExpression)super.createExpressionFromText(languageLevel, text);
|
||||
}
|
||||
|
||||
public abstract @NotNull PyPattern createPatternFromText(@NotNull LanguageLevel languageLevel, @NotNull String text) throws IncorrectOperationException;
|
||||
public abstract @NotNull PyPattern createPatternFromText(@NotNull LanguageLevel languageLevel, @NotNull String text)
|
||||
throws IncorrectOperationException;
|
||||
|
||||
/**
|
||||
* Adds elements to list inserting required commas.
|
||||
@@ -131,9 +133,9 @@ public abstract class PyElementGenerator extends PyAstElementGenerator {
|
||||
* @return created {@link PyFromImportStatement}
|
||||
*/
|
||||
public abstract @NotNull PyFromImportStatement createFromImportStatement(@NotNull LanguageLevel languageLevel,
|
||||
@NotNull String qualifier,
|
||||
@NotNull String name,
|
||||
@Nullable String alias);
|
||||
@NotNull String qualifier,
|
||||
@NotNull String name,
|
||||
@Nullable String alias);
|
||||
|
||||
/**
|
||||
* Creates import statement of form {@code import name as alias}.
|
||||
@@ -144,8 +146,8 @@ public abstract class PyElementGenerator extends PyAstElementGenerator {
|
||||
* @return created {@link PyImportStatement}
|
||||
*/
|
||||
public abstract @NotNull PyImportStatement createImportStatement(@NotNull LanguageLevel languageLevel,
|
||||
@NotNull String name,
|
||||
@Nullable String alias);
|
||||
@NotNull String name,
|
||||
@Nullable String alias);
|
||||
|
||||
public abstract @NotNull PyEllipsisLiteralExpression createEllipsis();
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ import com.jetbrains.python.ast.PyAstExceptPart;
|
||||
import com.jetbrains.python.psi.stubs.PyExceptPartStub;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PyExceptPart extends PyAstExceptPart, PyElement, StubBasedPsiElement<PyExceptPartStub>, PyNamedElementContainer, PyStatementPart {
|
||||
public interface PyExceptPart
|
||||
extends PyAstExceptPart, PyElement, StubBasedPsiElement<PyExceptPartStub>, PyNamedElementContainer, PyStatementPart {
|
||||
PyExceptPart[] EMPTY_ARRAY = new PyExceptPart[0];
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,5 +23,4 @@ public interface PyForPart extends PyAstForPart, PyStatementPart {
|
||||
default @Nullable PyExpression getSource() {
|
||||
return (PyExpression)PyAstForPart.super.getSource();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an f-string, a special kind of interpolated string literal introduced in Python 3.6.
|
||||
*
|
||||
* <p>
|
||||
* Unlike {@link PyPlainStringElement} these elements are composite and consist of several kinds of tokens
|
||||
* and normal PSI trees for embedded expressions.
|
||||
*
|
||||
*
|
||||
* @see com.jetbrains.python.PyTokenTypes#FSTRING_START
|
||||
* @see com.jetbrains.python.PyTokenTypes#FSTRING_TEXT
|
||||
* @see PyFStringFragment
|
||||
|
||||
@@ -14,10 +14,12 @@ import java.util.List;
|
||||
/**
|
||||
* Describes "from ... import" statements.
|
||||
*/
|
||||
public interface PyFromImportStatement extends PyAstFromImportStatement, PyImportStatementBase, StubBasedPsiElement<PyFromImportStatementStub>,
|
||||
PyImplicitImportNameDefiner {
|
||||
public interface PyFromImportStatement
|
||||
extends PyAstFromImportStatement, PyImportStatementBase, StubBasedPsiElement<PyFromImportStatementStub>,
|
||||
PyImplicitImportNameDefiner {
|
||||
/**
|
||||
* Returns a reference the module from which import is required.
|
||||
*
|
||||
* @return reference to module. If the 'from' reference is relative and consists entirely of dots, null is returned.
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -41,9 +41,9 @@ public interface PyFunction extends PyAstFunction, StubBasedPsiElement<PyFunctio
|
||||
|
||||
/**
|
||||
* Infers function's return type by analyzing <b>return statements</b> (including implicit returns) and <b>yield expression</b>.
|
||||
* In contrast with {@link TypeEvalContext#getReturnType(PyCallable)} does not consider
|
||||
* In contrast with {@link TypeEvalContext#getReturnType(PyCallable)} does not consider
|
||||
* return type annotations or any other {@link PyTypeProvider}.
|
||||
*
|
||||
*
|
||||
* @apiNote Does not cache the result.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@@ -55,8 +55,8 @@ public interface PyFunction extends PyAstFunction, StubBasedPsiElement<PyFunctio
|
||||
* This includes explicit 'return' statements and statements that can complete
|
||||
* normally with an implicit 'return None', excluding statements that raise exceptions.
|
||||
*
|
||||
* @see PyFunction#getReturnStatementType(TypeEvalContext)
|
||||
* @return List of exit point statements, in control flow order
|
||||
* @see PyFunction#getReturnStatementType(TypeEvalContext)
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NotNull
|
||||
@@ -78,6 +78,7 @@ public interface PyFunction extends PyAstFunction, StubBasedPsiElement<PyFunctio
|
||||
/**
|
||||
* Searches for function attributes.
|
||||
* See <a href="http://legacy.python.org/dev/peps/pep-0232/">PEP-0232</a>
|
||||
*
|
||||
* @return assignment statements for function attributes
|
||||
*/
|
||||
@NotNull
|
||||
|
||||
@@ -6,5 +6,6 @@ import com.jetbrains.python.ast.PyAstImportStatement;
|
||||
import com.jetbrains.python.psi.stubs.PyImportStatementStub;
|
||||
|
||||
|
||||
public interface PyImportStatement extends PyAstImportStatement, PyImportStatementBase, StubBasedPsiElement<PyImportStatementStub>, PyImplicitImportNameDefiner {
|
||||
public interface PyImportStatement
|
||||
extends PyAstImportStatement, PyImportStatementBase, StubBasedPsiElement<PyImportStatementStub>, PyImplicitImportNameDefiner {
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public interface PyKeyValueExpression extends PyAstKeyValueExpression, PyExpression {
|
||||
PyKeyValueExpression[] EMPTY_ARRAY = new PyKeyValueExpression[0];
|
||||
PyKeyValueExpression[] EMPTY_ARRAY = new PyKeyValueExpression[0];
|
||||
|
||||
@Override
|
||||
default @NotNull PyExpression getKey() {
|
||||
|
||||
@@ -15,8 +15,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
/**
|
||||
* Represents a named parameter, as opposed to a tuple parameter.
|
||||
*/
|
||||
public interface PyNamedParameter extends PyAstNamedParameter, PyParameter, PsiNamedElement, PsiNameIdentifierOwner, PyExpression, PyTypeCommentOwner,
|
||||
PyAnnotationOwner, StubBasedPsiElement<PyNamedParameterStub> {
|
||||
public interface PyNamedParameter
|
||||
extends PyAstNamedParameter, PyParameter, PsiNamedElement, PsiNameIdentifierOwner, PyExpression, PyTypeCommentOwner,
|
||||
PyAnnotationOwner, StubBasedPsiElement<PyNamedParameterStub> {
|
||||
|
||||
@Override
|
||||
default @Nullable PyExpression getDefaultValue() {
|
||||
|
||||
@@ -20,7 +20,8 @@ public abstract class PyPsiFacade {
|
||||
return project.getService(PyPsiFacade.class);
|
||||
}
|
||||
|
||||
public abstract @NotNull List<PsiElement> resolveQualifiedName(@NotNull QualifiedName name, @NotNull PyQualifiedNameResolveContext context);
|
||||
public abstract @NotNull List<PsiElement> resolveQualifiedName(@NotNull QualifiedName name,
|
||||
@NotNull PyQualifiedNameResolveContext context);
|
||||
|
||||
public abstract @NotNull PyQualifiedNameResolveContext createResolveContextFromFoothold(@NotNull PsiElement foothold);
|
||||
|
||||
|
||||
@@ -16,5 +16,6 @@ public interface PyQualifiedNameOwner extends PyAstQualifiedNameOwner, PyElement
|
||||
* is contained inside an element that doesn't have a qualified name.
|
||||
*/
|
||||
@Nullable
|
||||
@NlsSafe String getQualifiedName();
|
||||
@NlsSafe
|
||||
String getQualifiedName();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public interface PyReferenceExpression extends PyAstReferenceExpression, PyQuali
|
||||
* <i>Note: the returned list does not contain null values.</i>
|
||||
*/
|
||||
default @NotNull List<QualifiedRatedResolveResult> multiFollowAssignmentsChain(@NotNull PyResolveContext resolveContext) {
|
||||
return multiFollowAssignmentsChain(resolveContext, __->true);
|
||||
return multiFollowAssignmentsChain(resolveContext, __ -> true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +51,7 @@ public interface PyReferenceExpression extends PyAstReferenceExpression, PyQuali
|
||||
* Starts at this, expecting it to resolve to a target of an assignment.
|
||||
*
|
||||
* @param resolveContext resolve context
|
||||
* @param follow predicate to test if target should be followed
|
||||
* @param follow predicate to test if target should be followed
|
||||
* @return the values that could be assigned to this element via a chain of assignments, or an empty list.
|
||||
* <i>Note: the returned list does not contain null values.</i>
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,6 @@ import com.jetbrains.python.ast.PyAstSequencePattern
|
||||
import com.jetbrains.python.ast.findChildrenByClass
|
||||
|
||||
interface PySequencePattern : PyAstSequencePattern, PyPattern {
|
||||
val elements: List<PyPattern>
|
||||
val elements: List<PyPattern>
|
||||
get() = findChildrenByClass(PyPattern::class.java).toList()
|
||||
}
|
||||
|
||||
@@ -22,5 +22,6 @@ import com.jetbrains.python.psi.stubs.PyStarImportElementStub;
|
||||
/**
|
||||
* Marks the star in "from foo import *".
|
||||
*/
|
||||
public interface PyStarImportElement extends PyAstStarImportElement, PyImplicitImportNameDefiner, StubBasedPsiElement<PyStarImportElementStub> {
|
||||
public interface PyStarImportElement
|
||||
extends PyAstStarImportElement, PyImplicitImportNameDefiner, StubBasedPsiElement<PyStarImportElementStub> {
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ import com.jetbrains.python.ast.PyAstStatement;
|
||||
* Everything that may be an element of a statement list.
|
||||
*/
|
||||
public interface PyStatement extends PyAstStatement, PyElement {
|
||||
PyStatement[] EMPTY_ARRAY = new PyStatement[0];
|
||||
PyStatement[] EMPTY_ARRAY = new PyStatement[0];
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* A string literal expression can consist of a number of implicitly concatenated string literals
|
||||
* each with its own set of quotes and prefixes. For instance, the following string literal expression
|
||||
* each with its own set of quotes and prefixes. For instance, the following string literal expression
|
||||
* in the right hand side of the assignment:
|
||||
* <p>
|
||||
* <code><pre>
|
||||
@@ -27,13 +27,14 @@ import java.util.List;
|
||||
* decoded value, etc.
|
||||
*
|
||||
* @see <a href="https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation">
|
||||
* https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation</a>
|
||||
* https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation</a>
|
||||
* @see #getStringElements()
|
||||
* @see PyStringElement
|
||||
* @see PyPlainStringElement
|
||||
* @see PyFormattedStringElement
|
||||
*/
|
||||
public interface PyStringLiteralExpression extends PyAstStringLiteralExpression, PyLiteralExpression, StringLiteralExpression, PsiLanguageInjectionHost {
|
||||
public interface PyStringLiteralExpression
|
||||
extends PyAstStringLiteralExpression, PyLiteralExpression, StringLiteralExpression, PsiLanguageInjectionHost {
|
||||
/**
|
||||
* Returns a list of implicitly concatenated string elements composing this literal expression.
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public interface PySubscriptionExpression extends PyAstSubscriptionExpression, PyQualifiedExpression, PyCallSiteExpression, PyReferenceOwner {
|
||||
public interface PySubscriptionExpression
|
||||
extends PyAstSubscriptionExpression, PyQualifiedExpression, PyCallSiteExpression, PyReferenceOwner {
|
||||
|
||||
/**
|
||||
* @return For {@code spam[x][y][n]} will return {@code spam} regardless number of its dimensions
|
||||
|
||||
@@ -11,8 +11,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
/**
|
||||
* Represents Type Alias Statement added in <a href="https://peps.python.org/pep-0695/">PEP 695</a>
|
||||
*/
|
||||
public interface PyTypeAliasStatement extends PyAstTypeAliasStatement, PyStatement, PsiNameIdentifierOwner, PyTypeParameterListOwner, PyTypedElement,
|
||||
StubBasedPsiElement<PyTypeAliasStatementStub>, PyQualifiedNameOwner, ScopeOwner {
|
||||
public interface PyTypeAliasStatement
|
||||
extends PyAstTypeAliasStatement, PyStatement, PsiNameIdentifierOwner, PyTypeParameterListOwner, PyTypedElement,
|
||||
StubBasedPsiElement<PyTypeAliasStatementStub>, PyQualifiedNameOwner, ScopeOwner {
|
||||
|
||||
@Override
|
||||
default @Nullable PyExpression getTypeExpression() {
|
||||
|
||||
@@ -11,7 +11,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
* Represents a Type Parameter that can be a part of {@link PyTypeParameterList}<br>
|
||||
* For more information see <a href="https://peps.python.org/pep-0695/">PEP 695</a>
|
||||
*/
|
||||
public interface PyTypeParameter extends PyAstTypeParameter, PyElement, PsiNameIdentifierOwner, PyTypedElement, PyQualifiedNameOwner, StubBasedPsiElement<PyTypeParameterStub> {
|
||||
public interface PyTypeParameter extends PyAstTypeParameter, PyElement, PsiNameIdentifierOwner, PyTypedElement, PyQualifiedNameOwner,
|
||||
StubBasedPsiElement<PyTypeParameterStub> {
|
||||
|
||||
@Override
|
||||
default @Nullable PyExpression getBoundExpression() {
|
||||
|
||||
@@ -59,6 +59,7 @@ public final class PyPsiUtils {
|
||||
|
||||
/**
|
||||
* Finds first sibling that is neither comment, nor whitespace before given element.
|
||||
*
|
||||
* @param strict prohibit returning element itself
|
||||
*/
|
||||
public static @Nullable PsiElement getPrevNonCommentSibling(@Nullable PsiElement start, boolean strict) {
|
||||
@@ -109,6 +110,7 @@ public final class PyPsiUtils {
|
||||
|
||||
/**
|
||||
* Finds first sibling that is neither comment, nor whitespace after given element.
|
||||
*
|
||||
* @param strict prohibit returning element itself
|
||||
*/
|
||||
public static @Nullable PsiElement getNextNonCommentSibling(@Nullable PsiElement start, boolean strict) {
|
||||
@@ -117,6 +119,7 @@ public final class PyPsiUtils {
|
||||
|
||||
/**
|
||||
* Finds first token after given element that doesn't consist solely of spaces and is not empty (e.g. error marker).
|
||||
*
|
||||
* @param ignoreComments ignore commentaries as well
|
||||
*/
|
||||
public static @Nullable PsiElement getNextSignificantLeaf(@Nullable PsiElement element, boolean ignoreComments) {
|
||||
@@ -128,6 +131,7 @@ public final class PyPsiUtils {
|
||||
|
||||
/**
|
||||
* Finds first token before given element that doesn't consist solely of spaces and is not empty (e.g. error marker).
|
||||
*
|
||||
* @param ignoreComments ignore commentaries as well
|
||||
*/
|
||||
public static @Nullable PsiElement getPrevSignificantLeaf(@Nullable PsiElement element, boolean ignoreComments) {
|
||||
@@ -261,7 +265,8 @@ public final class PyPsiUtils {
|
||||
public static boolean isMethodContext(final PsiElement element) {
|
||||
final PsiNamedElement parent = PsiTreeUtil.getParentOfType(element, PyFile.class, PyFunction.class, PyClass.class);
|
||||
// In case if element is inside method which is inside class
|
||||
if (parent instanceof PyFunction && PsiTreeUtil.getParentOfType(parent, PyFile.class, PyFunction.class, PyClass.class) instanceof PyClass) {
|
||||
if (parent instanceof PyFunction &&
|
||||
PsiTreeUtil.getParentOfType(parent, PyFile.class, PyFunction.class, PyClass.class) instanceof PyClass) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -302,6 +307,7 @@ public final class PyPsiUtils {
|
||||
/**
|
||||
* Returns comments preceding given elements as pair of the first and the last such comments. Comments should not be
|
||||
* separated by any empty line.
|
||||
*
|
||||
* @param element element comments should be adjacent to
|
||||
* @return described range or {@code null} if there are no such comments
|
||||
*/
|
||||
@@ -348,7 +354,7 @@ public final class PyPsiUtils {
|
||||
* def func():
|
||||
* pass
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that in the following case it will additionally return an empty list of comments as the last element
|
||||
* to distinguish between the cases when there is a blank line above the provided element and when there is not.
|
||||
*
|
||||
|
||||
+20
@@ -32,42 +32,62 @@ import org.jetbrains.annotations.Nullable;
|
||||
public interface PyQualifiedNameResolveContext {
|
||||
@Nullable
|
||||
PsiElement getFoothold();
|
||||
|
||||
int getRelativeLevel();
|
||||
|
||||
@Nullable
|
||||
Sdk getSdk();
|
||||
|
||||
@Nullable
|
||||
Module getModule();
|
||||
|
||||
@NotNull
|
||||
Project getProject();
|
||||
|
||||
boolean getWithoutRoots();
|
||||
|
||||
boolean getWithoutForeign();
|
||||
|
||||
boolean getWithoutStubs();
|
||||
|
||||
@NotNull
|
||||
PsiManager getPsiManager();
|
||||
|
||||
boolean getWithMembers();
|
||||
|
||||
boolean getWithPlainDirectories();
|
||||
|
||||
boolean getVisitAllModules();
|
||||
|
||||
@Nullable
|
||||
Sdk getEffectiveSdk();
|
||||
|
||||
boolean isValid();
|
||||
|
||||
@Nullable
|
||||
PsiFile getFootholdFile();
|
||||
|
||||
@Nullable
|
||||
PsiDirectory getContainingDirectory();
|
||||
|
||||
@NotNull
|
||||
PyQualifiedNameResolveContext copyWithoutForeign();
|
||||
|
||||
@NotNull
|
||||
PyQualifiedNameResolveContext copyWithMembers();
|
||||
|
||||
@NotNull
|
||||
PyQualifiedNameResolveContext copyWithPlainDirectories();
|
||||
|
||||
@NotNull
|
||||
PyQualifiedNameResolveContext copyWithRelative(int relativeLevel);
|
||||
|
||||
@NotNull
|
||||
PyQualifiedNameResolveContext copyWithoutRoots();
|
||||
|
||||
@NotNull
|
||||
PyQualifiedNameResolveContext copyWithRoots();
|
||||
|
||||
@NotNull
|
||||
PyQualifiedNameResolveContext copyWithoutStubs();
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import java.util.List;
|
||||
|
||||
public interface PyFileStub extends PsiFileStub<PyFile> {
|
||||
List<String> getDunderAll();
|
||||
|
||||
BitSet getFutureFeatures();
|
||||
|
||||
String getDeprecationMessage();
|
||||
}
|
||||
|
||||
@@ -6,9 +6,13 @@ import com.jetbrains.python.psi.PyFunction;
|
||||
|
||||
public interface PyFunctionStub extends NamedStub<PyFunction>, PyAnnotationOwnerStub, PyTypeCommentOwnerStub, PyVersionSpecificStub {
|
||||
String getDocString();
|
||||
|
||||
String getDeprecationMessage();
|
||||
|
||||
boolean isAsync();
|
||||
|
||||
boolean isGenerator();
|
||||
|
||||
default boolean onlyRaisesNotImplementedError() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
package com.jetbrains.python.psi.stubs;
|
||||
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.jetbrains.python.psi.PyImportElement;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.jetbrains.python.psi.PyImportElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public interface PyImportElementStub extends StubElement<PyImportElement> {
|
||||
@Nullable
|
||||
QualifiedName getImportedQName();
|
||||
|
||||
|
||||
String getAsName();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PyNamedParameterStub extends NamedStub<PyNamedParameter>, PyAnnotationOwnerStub, PyTypeCommentOwnerStub {
|
||||
boolean isPositionalContainer();
|
||||
|
||||
boolean isKeywordContainer();
|
||||
|
||||
default @Nullable String getDefaultValueText() {
|
||||
|
||||
@@ -18,7 +18,8 @@ public interface PyCallableParameter {
|
||||
* Returns null if the parameter is tuple or star, or name is unknown.
|
||||
*/
|
||||
@Nullable
|
||||
@Nls String getName();
|
||||
@Nls
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* @param context type evaluation context
|
||||
|
||||
@@ -32,6 +32,7 @@ public interface PyClassLikeType extends PyCallableType, PyWithAncestors, PyInst
|
||||
boolean inherited);
|
||||
|
||||
// TODO: Pull to PyType at next iteration
|
||||
|
||||
/**
|
||||
* Visits all class members. This method is better then bare class since it uses type info and supports not only classes but
|
||||
* class-like structures as well. Consider using user-friendly wrapper {@link PyTypeUtil#getMembersOfType(PyClassLikeType, Class, boolean, TypeEvalContext)}
|
||||
|
||||
+3
-3
@@ -39,9 +39,9 @@ public class PyClassMembersProviderBase implements PyClassMembersProvider {
|
||||
* @return found member or null
|
||||
*/
|
||||
public static @Nullable PsiElement resolveMemberByName(@NotNull Collection<? extends PyCustomMember> members,
|
||||
@NotNull String name,
|
||||
@NotNull PsiElement context,
|
||||
@NotNull PyResolveContext resolveContext) {
|
||||
@NotNull String name,
|
||||
@NotNull PsiElement context,
|
||||
@NotNull PyResolveContext resolveContext) {
|
||||
for (PyCustomMember member : members) {
|
||||
if (member.getName().equals(name)) {
|
||||
return member.resolve(context, resolveContext);
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.jetbrains.python.psi.types;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A type that can describe either particular instantiated instance of a class or a class itself.
|
||||
*
|
||||
* A type that can describe either particular instantiated instance of a class or a class itself.
|
||||
*
|
||||
* @author Mikhail Golubev
|
||||
*/
|
||||
public interface PyInstantiableType<T extends PyInstantiableType<T>> extends PyType {
|
||||
|
||||
+5
-3
@@ -27,7 +27,9 @@ public abstract class PyModuleMembersProvider {
|
||||
* @param context type evaluation context
|
||||
* @return provided members
|
||||
*/
|
||||
public @NotNull Collection<PyCustomMember> getMembers(@NotNull PyFile module, @NotNull PointInImport point, @NotNull TypeEvalContext context) {
|
||||
public @NotNull Collection<PyCustomMember> getMembers(@NotNull PyFile module,
|
||||
@NotNull PointInImport point,
|
||||
@NotNull TypeEvalContext context) {
|
||||
final VirtualFile vFile = module.getVirtualFile();
|
||||
if (vFile != null) {
|
||||
final String qName = PyPsiFacade.getInstance(module.getProject()).findShortestImportableName(vFile, module);
|
||||
@@ -64,6 +66,6 @@ public abstract class PyModuleMembersProvider {
|
||||
* @return provided members
|
||||
*/
|
||||
protected abstract @NotNull Collection<PyCustomMember> getMembersByQName(@NotNull PyFile module,
|
||||
@NotNull String qName,
|
||||
@NotNull TypeEvalContext context);
|
||||
@NotNull String qName,
|
||||
@NotNull TypeEvalContext context);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.jetbrains.python.psi.PyExpression
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult
|
||||
|
||||
class PyNeverType private constructor(private val name: String): PyType {
|
||||
class PyNeverType private constructor(private val name: String) : PyType {
|
||||
companion object {
|
||||
@JvmField val NEVER: PyNeverType = PyNeverType("Never")
|
||||
@JvmField val NO_RETURN: PyNeverType = PyNeverType("NoReturn")
|
||||
@@ -16,7 +16,7 @@ class PyNeverType private constructor(private val name: String): PyType {
|
||||
@JvmStatic
|
||||
fun PyType?.toNoReturnIfNeeded(): PyType? = if (this === NEVER) NO_RETURN else this
|
||||
}
|
||||
|
||||
|
||||
override fun getName(): String = name
|
||||
override fun isBuiltin(): Boolean = true
|
||||
override fun assertValid(message: String?) {}
|
||||
@@ -30,7 +30,7 @@ class PyNeverType private constructor(private val name: String): PyType {
|
||||
direction: AccessDirection,
|
||||
resolveContext: PyResolveContext,
|
||||
): List<RatedResolveResult> = emptyList()
|
||||
|
||||
|
||||
override fun getCompletionVariants(
|
||||
completionPrefix: String?,
|
||||
location: PsiElement?,
|
||||
|
||||
@@ -35,7 +35,9 @@ public class PyTypeProviderBase implements PyTypeProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Ref<PyType> getParameterType(@NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) {
|
||||
public @Nullable Ref<PyType> getParameterType(@NotNull PyNamedParameter param,
|
||||
@NotNull PyFunction func,
|
||||
@NotNull TypeEvalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -45,7 +47,9 @@ public class PyTypeProviderBase implements PyTypeProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Ref<PyType> getCallType(@NotNull PyFunction function, @NotNull PyCallSiteExpression callSite, @NotNull TypeEvalContext context) {
|
||||
public @Nullable Ref<PyType> getCallType(@NotNull PyFunction function,
|
||||
@NotNull PyCallSiteExpression callSite,
|
||||
@NotNull TypeEvalContext context) {
|
||||
final ReturnTypeDescriptor descriptor;
|
||||
synchronized (myMethodToReturnTypeMap) {
|
||||
descriptor = myMethodToReturnTypeMap.get(function.getName());
|
||||
@@ -120,7 +124,9 @@ public class PyTypeProviderBase implements PyTypeProvider {
|
||||
myStringToReturnTypeMap.put(classQualifiedName, callback);
|
||||
}
|
||||
|
||||
public @Nullable Ref<PyType> get(@NotNull PyFunction function, @Nullable PyCallSiteExpression callSite, @NotNull TypeEvalContext context) {
|
||||
public @Nullable Ref<PyType> get(@NotNull PyFunction function,
|
||||
@Nullable PyCallSiteExpression callSite,
|
||||
@NotNull TypeEvalContext context) {
|
||||
return Optional
|
||||
.ofNullable(function.getContainingClass())
|
||||
.map(pyClass -> myStringToReturnTypeMap.get(pyClass.getQualifiedName()))
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
* Because the "unknown" type is historically represented as {@code null} in the type system, {@code PyTypeVisitor.visitPyType(type, visitor)}
|
||||
* should be used instead of direct {@code type.acceptTypeVisitor(visitor)} to properly account for possible {@code null} values.
|
||||
* <p>
|
||||
* This class gives access only to the types declared in the <tt>intellij.python.psi</tt> module.
|
||||
* This class gives access only to the types declared in the <tt>intellij.python.psi</tt> module.
|
||||
* Most actual implementations should extend {@link PyTypeVisitorExt}.
|
||||
* <p>
|
||||
* There are helper {@link PyRecursiveTypeVisitor} and {@link PyCloningTypeVisitor} for recursive type
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @see PyRecursiveTypeVisitor
|
||||
* @see PyCloningTypeVisitor
|
||||
* @see PyType#acceptTypeVisitor(PyTypeVisitor)
|
||||
* @see #visit(PyType, PyTypeVisitor)
|
||||
* @see #visit(PyType, PyTypeVisitor)
|
||||
* @see #visitUnknownType()
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@@ -74,7 +74,7 @@ public abstract class PyTypeVisitor<T> {
|
||||
public T visitPyCallableParameterListType(@NotNull PyCallableParameterListType callableParameterListType) {
|
||||
return visitPyType(callableParameterListType);
|
||||
}
|
||||
|
||||
|
||||
public T visitPyNeverType(@NotNull PyNeverType neverType) {
|
||||
return visitPyType(neverType);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public final class TypeEvalConstraints {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TypeEvalConstraints that)) return false;
|
||||
|
||||
return myAllowDataFlow == that.myAllowDataFlow &&
|
||||
return myAllowDataFlow == that.myAllowDataFlow &&
|
||||
myAllowStubToAST == that.myAllowStubToAST &&
|
||||
myAllowCallContext == that.myAllowCallContext &&
|
||||
Objects.equals(myOrigin, that.myOrigin);
|
||||
|
||||
@@ -268,7 +268,9 @@ public sealed class TypeEvalContext {
|
||||
myConstraints.myAllowStubToAST,
|
||||
myConstraints.myAllowCallContext,
|
||||
// code completion will always have a new PsiFile, use original file instead
|
||||
myConstraints.myOrigin != null ? myConstraints.myOrigin.getOriginalFile() : null);
|
||||
myConstraints.myOrigin != null
|
||||
? myConstraints.myOrigin.getOriginalFile()
|
||||
: null);
|
||||
return project.getService(TypeEvalContextCache.class).getLibraryContext(new LibraryTypeEvalContext(constraints));
|
||||
}
|
||||
|
||||
@@ -430,7 +432,7 @@ public sealed class TypeEvalContext {
|
||||
}
|
||||
|
||||
private static class PyNullType implements PyType {
|
||||
private PyNullType() {}
|
||||
private PyNullType() { }
|
||||
|
||||
@Override
|
||||
public @Nullable List<? extends RatedResolveResult> resolveMember(@NotNull String name,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Checks <code>typing.assert_type(val, typ, /)</code> calls and reports cases when <code>val</code>'s inferred type is not
|
||||
<code>typ</code>.
|
||||
Checks <code>typing.assert_type(val, typ, /)</code> calls and reports cases when <code>val</code>'s inferred type is not
|
||||
<code>typ</code>.
|
||||
</p>
|
||||
<p><b>Example:</b></p>
|
||||
<pre><code>
|
||||
|
||||
+2
-1
@@ -6,7 +6,8 @@
|
||||
and <code>typing.cast</code> does not dynamically validate the type.</p>
|
||||
|
||||
<p>This check applies even to types that could theoretically have a common descendant.
|
||||
For example, it will flag a cast between two sibling classes <code>Left</code> and <code>Right</code> that both inherit from <code>Top</code>,
|
||||
For example, it will flag a cast between two sibling classes <code>Left</code> and <code>Right</code> that both inherit from
|
||||
<code>Top</code>,
|
||||
because there is no direct inheritance relationship between them.</p>
|
||||
|
||||
<p><b>Example:</b></p>
|
||||
|
||||
+2
-1
@@ -14,4 +14,5 @@ class Account:
|
||||
</code></pre>
|
||||
<p>As a fix, you might want to check and modify the algorithm to ensure that reassignment is needed. If everything is correct,
|
||||
you can invoke intention actions for this code and opt to ignore the warning.</p>
|
||||
</body></html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>Reports type errors in function call expressions, targets, and return values. In a dynamically typed language, this is possible in a limited number of cases. </p>
|
||||
<p>Reports type errors in function call expressions, targets, and return values. In a dynamically typed language, this is possible in a
|
||||
limited number of cases. </p>
|
||||
<p>Types of function parameters can be specified in
|
||||
docstrings or in Python 3 function annotations.</p>
|
||||
<p><b>Example:</b></p>
|
||||
|
||||
@@ -17,6 +17,7 @@ def c(p1, p2): # Type signature has too many arguments
|
||||
# type: (int) -> int
|
||||
pass
|
||||
</code></pre>
|
||||
<p>Available quick-fixes offer various actions. You can rename, remove, or move problematic elements. You can also manually modify type declarations to ensure no warning is shown.</p>
|
||||
<p>Available quick-fixes offer various actions. You can rename, remove, or move problematic elements. You can also manually modify type
|
||||
declarations to ensure no warning is shown.</p>
|
||||
</body>
|
||||
</html>
|
||||
+2
-1
@@ -10,4 +10,5 @@ else:
|
||||
</code></pre>
|
||||
<p>As a fix, you might want to check and modify the algorithm to ensure it implements
|
||||
the expected logic.</p>
|
||||
</body></html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
<p>
|
||||
Reports local variables, parameters, and functions that are locally defined, but not used name in a function.
|
||||
</p>
|
||||
</body></html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ This intention converts string formatting via <code>format()</code> method and f
|
||||
</span>
|
||||
<!-- tooltip end -->
|
||||
<span>
|
||||
F-strings provide a way to embed expressions inside string literals, using a minimal syntax. See more details in <a href="https://www.python.org/dev/peps/pep-0498/">PEP-498</a>.
|
||||
F-strings provide a way to embed expressions inside string literals, using a minimal syntax. See more details in <a
|
||||
href="https://www.python.org/dev/peps/pep-0498/">PEP-498</a>.
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
<span>
|
||||
Converts <a href="https://www.python.org/dev/peps/pep-0484/">PEP-484</a> type comments to Python 3.6 <a href="https://www.python.org/dev/peps/pep-0526/">variable annotations</a>.
|
||||
Converts <a href="https://www.python.org/dev/peps/pep-0484/">PEP-484</a> type comments to Python 3.6 <a
|
||||
href="https://www.python.org/dev/peps/pep-0526/">variable annotations</a>.
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
||||
@@ -116,7 +116,7 @@ public final class PyNewStyleStringFormatParser {
|
||||
int autoFieldNumber = myImplicitlyNumberedFieldsCounter;
|
||||
|
||||
// in the order of appearance inside a field
|
||||
final IntList attrAndLookupBounds=new IntArrayList();
|
||||
final IntList attrAndLookupBounds = new IntArrayList();
|
||||
int conversionStart = -1;
|
||||
int formatSpecStart = -1;
|
||||
final List<Field> nestedFields = new ArrayList<>();
|
||||
|
||||
@@ -33,7 +33,8 @@ public final class PyPsiBundle extends DynamicBundle {
|
||||
return INSTANCE.getMessage(key, params);
|
||||
}
|
||||
|
||||
public static @NotNull Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
|
||||
public static @NotNull Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key,
|
||||
Object @NotNull ... params) {
|
||||
return INSTANCE.getLazyMessage(key, params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ object PyPsiPackageUtil {
|
||||
return buildMap {
|
||||
try {
|
||||
val resourceAsStream = requireNotNull(PyPsiPackageUtil::class.java.getClassLoader().getResourceAsStream("tools/packages"))
|
||||
{ "tool/packages is missed in distribution "}
|
||||
{ "tool/packages is missed in distribution " }
|
||||
for (line in ResourceUtil.loadText(resourceAsStream).lines()) {
|
||||
val split = line.trim().split(" ")
|
||||
check(split.size == 2) { "Each line should contain exactly two names: $line" }
|
||||
|
||||
@@ -289,8 +289,8 @@ public class PyStringFormatParser {
|
||||
myPos = 0;
|
||||
while (myPos < myLiteral.length()) {
|
||||
int next = myLiteral.indexOf('%', myPos);
|
||||
while(next >= 0 && next < myLiteral.length()-1 && myLiteral.charAt(next+1) == '%') {
|
||||
next = myLiteral.indexOf('%', next+2);
|
||||
while (next >= 0 && next < myLiteral.length() - 1 && myLiteral.charAt(next + 1) == '%') {
|
||||
next = myLiteral.indexOf('%', next + 2);
|
||||
}
|
||||
if (next < 0) break;
|
||||
if (next > myPos) {
|
||||
@@ -474,7 +474,7 @@ public class PyStringFormatParser {
|
||||
chunk.setMappingKey(myLiteral.substring(myPos + 1, mappingEnd));
|
||||
myPos = mappingEnd + 1;
|
||||
}
|
||||
else {
|
||||
else {
|
||||
chunk.setAutoPosition(mySubstitutionsCount);
|
||||
mySubstitutionsCount++;
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
open class PythonDocumentationHighlightingService {
|
||||
companion object{
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): PythonDocumentationHighlightingService {
|
||||
return service()
|
||||
|
||||
@@ -75,5 +75,4 @@ public class PythonParserDefinition implements ParserDefinition {
|
||||
// see LanguageTokenSeparatorGenerator instead
|
||||
return SpaceRequirements.MAY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,8 @@ public final class PythonTemplateRunner {
|
||||
if (editor != null) {
|
||||
Template template = builder.buildInlineTemplate();
|
||||
TemplateManager.getInstance(project).startTemplate(editor, template);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.runNonInteractively(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ import java.util.List;
|
||||
@ApiStatus.Experimental
|
||||
public class PythonUiService {
|
||||
|
||||
public void showBalloonInfo(Project project, @PopupContent String message) {}
|
||||
public void showBalloonInfo(Project project, @PopupContent String message) { }
|
||||
|
||||
public void showBalloonWarning(Project project, @PopupContent String message) {}
|
||||
public void showBalloonWarning(Project project, @PopupContent String message) { }
|
||||
|
||||
public void showBalloonError(Project project, @PopupContent String message) {}
|
||||
public void showBalloonError(Project project, @PopupContent String message) { }
|
||||
|
||||
public FileEditor getSelectedEditor(@NotNull Project project, VirtualFile virtualFile) {
|
||||
return null;
|
||||
@@ -55,7 +55,7 @@ public class PythonUiService {
|
||||
PsiElement element,
|
||||
String newName,
|
||||
boolean searchInComments,
|
||||
boolean searchTextOccurrences) {}
|
||||
boolean searchTextOccurrences) { }
|
||||
|
||||
public LocalQuickFix createPyChangeSignatureQuickFixForMismatchingMethods(PyFunction function, PyFunction method) {
|
||||
return null;
|
||||
@@ -119,6 +119,5 @@ public class PythonUiService {
|
||||
@ListItem String initialValue,
|
||||
@Nullable Icon icon) {
|
||||
return -1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,8 @@ private fun getInvertedConditionExpression(
|
||||
level: LanguageLevel,
|
||||
generator: PyElementGenerator,
|
||||
expression: PyExpression,
|
||||
isTopLevelExpression: Boolean): PyExpression {
|
||||
isTopLevelExpression: Boolean,
|
||||
): PyExpression {
|
||||
if (expression is PyParenthesizedExpression) {
|
||||
return getInvertedConditionExpression(
|
||||
project, file, level, generator, expression.containedExpression!!, isTopLevelExpression)
|
||||
@@ -271,7 +272,8 @@ private fun requiresParentheses(element: PsiElement): Boolean {
|
||||
}
|
||||
|
||||
private fun createOrExpression(
|
||||
level: LanguageLevel, generator: PyElementGenerator, expressions: Iterable<PyExpression>, isTopLevelExpression: Boolean): PyExpression {
|
||||
level: LanguageLevel, generator: PyElementGenerator, expressions: Iterable<PyExpression>, isTopLevelExpression: Boolean,
|
||||
): PyExpression {
|
||||
val result = StringBuilder()
|
||||
|
||||
val requiresParentheses = !isTopLevelExpression && expressions.count() > 1
|
||||
|
||||
-1
@@ -57,5 +57,4 @@ public final class PyDataclassClassMembersProvider extends PyClassMembersProvide
|
||||
return CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ fun resolvesToOmittedDefault(expression: PyExpression, type: Type): Boolean {
|
||||
val qNames = PyResolveUtil.resolveImportedElementQNameLocally(expression)
|
||||
|
||||
return when (type.asPredefinedType) {
|
||||
PyDataclassParameters.PredefinedType.STD, PyDataclassParameters.PredefinedType.DATACLASS_TRANSFORM ->
|
||||
PyDataclassParameters.PredefinedType.STD, PyDataclassParameters.PredefinedType.DATACLASS_TRANSFORM ->
|
||||
qNames.any { it.toString() == PyDataclassNames.Dataclasses.DATACLASSES_MISSING }
|
||||
PyDataclassParameters.PredefinedType.ATTRS -> qNames.any { it.toString() in PyDataclassNames.Attrs.ATTRS_NOTHING }
|
||||
else -> false
|
||||
@@ -245,28 +245,28 @@ private fun parseDataclassParametersFromAST(cls: PyClass, context: TypeEvalConte
|
||||
|
||||
for (decorator in decorators.decorators) {
|
||||
val callee = (decorator.callee as? PyReferenceExpression) ?: continue
|
||||
|
||||
|
||||
for (decoratorQualifiedName in PyResolveUtil.resolveImportedElementQNameLocally(callee)) {
|
||||
val types = decoratorAndTypeAndMarkedCallee(cls.project)
|
||||
val decoratorAndTypeAndMarkedCallee = types.firstOrNull { it.first == decoratorQualifiedName } ?: continue
|
||||
|
||||
|
||||
val mapping = decorator.mapArguments(
|
||||
PyCallableTypeImpl(decoratorAndTypeAndMarkedCallee.third, null),
|
||||
context ?: TypeEvalContext.codeInsightFallback(cls.project)
|
||||
)
|
||||
|
||||
|
||||
val builder = PyDataclassParametersBuilder(decoratorAndTypeAndMarkedCallee.second, decoratorAndTypeAndMarkedCallee.first)
|
||||
|
||||
|
||||
mapping
|
||||
.mappedParameters
|
||||
.entries
|
||||
.forEach {
|
||||
builder.update(it.value.name, it.key)
|
||||
}
|
||||
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
|
||||
// Process decorators that have dataclass_transform-compatible keyword arguments.
|
||||
if (decorator.qualifiedName == null) continue
|
||||
val decoratorKeywordArguments = decorator.arguments.filterIsInstance<PyKeywordArgument>()
|
||||
@@ -559,10 +559,10 @@ private fun resolveDataclassParameters(
|
||||
// TODO remove this hack, make it a proper field
|
||||
val extraArguments = mutableMapOf<String, PyExpression>()
|
||||
if (type.asPredefinedType == PyDataclassParameters.PredefinedType.ATTRS && stub.decoratorName() == PyKnownDecorator.ATTR_DATACLASS.qualifiedName) {
|
||||
extraArguments["auto_attribs"] =
|
||||
extraArguments["auto_attribs"] =
|
||||
PyElementGenerator.getInstance(pyClass.project).createExpressionFromText(LanguageLevel.forElement(pyClass), PyNames.TRUE)
|
||||
}
|
||||
|
||||
|
||||
return PyDataclassParameters(
|
||||
init = stub.initValue() ?: true,
|
||||
repr = stub.reprValue() ?: true,
|
||||
@@ -603,8 +603,8 @@ private fun resolveDataclassParameters(
|
||||
.overStub { dtStub -> dtStub }
|
||||
.withStubBuilder(PyDataclassTransformDecoratorStub::create)
|
||||
.compute(context)
|
||||
|
||||
|
||||
|
||||
|
||||
if (dataclassTransformStub != null) {
|
||||
val resolvedFieldSpecifiers = dataclassTransformStub.fieldSpecifiers
|
||||
.flatMap { PyResolveUtil.resolveQualifiedNameInScope(it, ScopeUtil.getScopeOwner(dataclassTransformDecorator)!!, context) }
|
||||
@@ -690,7 +690,7 @@ fun resolveDataclassFieldParameters(
|
||||
context: TypeEvalContext,
|
||||
): PyDataclassFieldParameters? {
|
||||
assert(field.containingClass == dataclass)
|
||||
|
||||
|
||||
val assignedQName = field.assignedQName
|
||||
if (assignedQName != null) {
|
||||
val resolvesToMissingOrNothing = PyResolveUtil.resolveQualifiedNameInScope(assignedQName, ScopeUtil.getScopeOwner(dataclass)!!, context)
|
||||
@@ -707,7 +707,7 @@ fun resolveDataclassFieldParameters(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val fieldStub = if (field.stub != null) {
|
||||
// TODO access the green stub here
|
||||
field.stub.getCustomStub(PyDataclassFieldStub::class.java)
|
||||
@@ -729,16 +729,16 @@ fun resolveDataclassFieldParameters(
|
||||
if (field.calleeName == null) return null
|
||||
val fieldSpecifierDeclaration = PyResolveUtil.resolveQualifiedNameInScope(field.calleeName!!, ScopeUtil.getScopeOwner(dataclass)!!, context)
|
||||
.filterIsInstance<PyQualifiedNameOwner>()
|
||||
.firstOrNull {
|
||||
.firstOrNull {
|
||||
val qualifiedName = it.qualifiedName
|
||||
qualifiedName != null && QualifiedName.fromDottedString(qualifiedName) in dataclassParams.fieldSpecifiers
|
||||
qualifiedName != null && QualifiedName.fromDottedString(qualifiedName) in dataclassParams.fieldSpecifiers
|
||||
}
|
||||
if (fieldSpecifierDeclaration == null) return null
|
||||
val fieldSpecifierCallable = when (fieldSpecifierDeclaration) {
|
||||
is PyClass -> fieldSpecifierDeclaration.findInitOrNew(true, context)
|
||||
is PyFunction -> fieldSpecifierDeclaration
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
if (fieldSpecifierCallable == null) return null
|
||||
return PyDataclassFieldParameters(
|
||||
hasDefault = fieldStub?.hasDefault() ?: false,
|
||||
|
||||
+9
-7
@@ -75,7 +75,7 @@ open class PySoftFileReferenceContributor : PsiReferenceContributor() {
|
||||
parameterNames.any(::matchesPathNamePattern)
|
||||
}
|
||||
.any {
|
||||
val mapping = callExpr.mapArguments( it, typeEvalContext)
|
||||
val mapping = callExpr.mapArguments(it, typeEvalContext)
|
||||
val parameterName = mapping.mappedParameters[expr]?.name ?: return@any false
|
||||
matchesPathNamePattern(parameterName)
|
||||
}
|
||||
@@ -110,12 +110,12 @@ open class PySoftFileReferenceContributor : PsiReferenceContributor() {
|
||||
val mapping = callExpr.mapArguments(it, typeEvalContext)
|
||||
mapping.mappedParameters[expr]?.getArgumentType(typeEvalContext)
|
||||
}
|
||||
|
||||
|
||||
// We can't use PyTypeChecker.match directly because the type `str | PathLike` is considered incompatible
|
||||
// with neither str nor PathLike (strict union semantics).
|
||||
fun PyType.allowsValuesCompatibleWith(superType: PyType): Boolean =
|
||||
fun PyType.allowsValuesCompatibleWith(superType: PyType): Boolean =
|
||||
PyTypeUtil.toStream(this).anyMatch { it != null && PyTypeChecker.match(superType, it, typeEvalContext) }
|
||||
|
||||
|
||||
return argumentTypes.any { it.allowsValuesCompatibleWith(bytesOrUnicodeType) } &&
|
||||
argumentTypes.any { it.allowsValuesCompatibleWith(osPathLikeType) }
|
||||
}
|
||||
@@ -207,9 +207,11 @@ open class PySoftFileReferenceContributor : PsiReferenceContributor() {
|
||||
override fun createFileReference(range: TextRange, index: Int, text: String): FileReference? =
|
||||
doCreateFileReference(range, index, expandUserHome(text))
|
||||
|
||||
open fun doCreateFileReference(range: TextRange,
|
||||
index: Int,
|
||||
expandedText: String?): FileReference? =
|
||||
open fun doCreateFileReference(
|
||||
range: TextRange,
|
||||
index: Int,
|
||||
expandedText: String?,
|
||||
): FileReference? =
|
||||
super.createFileReference(range, index, expandedText)
|
||||
|
||||
override fun isAbsolutePathReference(): Boolean =
|
||||
|
||||
+15
-8
@@ -104,7 +104,8 @@ public class PySubstitutionChunkReference extends PsiReferenceBase<PyStringLiter
|
||||
|
||||
private @NotNull Ref<PyExpression> resolveKeywordFormat(@NotNull PyArgumentList argumentList) {
|
||||
final Ref<PyExpression> valueExprRef = getKeyValueFromArguments(argumentList);
|
||||
final String indexElement = myChunk instanceof NewStyleSubstitutionChunk ? ((NewStyleSubstitutionChunk)myChunk).getMappingKeyElementIndex() : null;
|
||||
final String indexElement =
|
||||
myChunk instanceof NewStyleSubstitutionChunk ? ((NewStyleSubstitutionChunk)myChunk).getMappingKeyElementIndex() : null;
|
||||
if (valueExprRef != null && !valueExprRef.isNull() && indexElement != null) {
|
||||
final PyExpression valueExpr = PyPsiUtils.flattenParens(valueExprRef.get());
|
||||
assert valueExpr != null;
|
||||
@@ -130,7 +131,7 @@ public class PySubstitutionChunkReference extends PsiReferenceBase<PyStringLiter
|
||||
if (valueFromKeywordArg != null) {
|
||||
valueExprRef = Ref.create(valueFromKeywordArg.getValueExpression());
|
||||
}
|
||||
else if (!keywordStarArgs.isEmpty()){
|
||||
else if (!keywordStarArgs.isEmpty()) {
|
||||
for (PyStarArgument arg : keywordStarArgs) {
|
||||
final Ref<PyExpression> resolvedRef = resolveKeywordStarExpression(arg);
|
||||
if (resolvedRef != null && (valueExprRef == null || valueExprRef.get() == null)) {
|
||||
@@ -256,7 +257,9 @@ public class PySubstitutionChunkReference extends PsiReferenceBase<PyStringLiter
|
||||
return null;
|
||||
}
|
||||
boolean isKeyWordSubstitution = myChunk.getMappingKey() != null;
|
||||
return isKeyWordSubstitution ? resolveKeywordPercent(rightExpression, myChunk.getMappingKey()) : resolvePositionalPercent(rightExpression);
|
||||
return isKeyWordSubstitution
|
||||
? resolveKeywordPercent(rightExpression, myChunk.getMappingKey())
|
||||
: resolvePositionalPercent(rightExpression);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -297,7 +300,7 @@ public class PySubstitutionChunkReference extends PsiReferenceBase<PyStringLiter
|
||||
}
|
||||
}
|
||||
else if (myPosition != 0 && PsiTreeUtil.instanceOf(containedExpression, PyLiteralExpression.class, PySetLiteralExpression.class,
|
||||
PyListLiteralExpression.class, PyDictLiteralExpression.class)) {
|
||||
PyListLiteralExpression.class, PyDictLiteralExpression.class)) {
|
||||
return null;
|
||||
}
|
||||
return containedExpression;
|
||||
@@ -347,8 +350,9 @@ public class PySubstitutionChunkReference extends PsiReferenceBase<PyStringLiter
|
||||
|
||||
private @Nullable Ref<PyExpression> resolvePositionalStarExpression(@NotNull PyStarArgument starArgument, int argumentPosition) {
|
||||
assert myPosition >= 0;
|
||||
final PyExpression expr = PyPsiUtils.flattenParens(PsiTreeUtil.getChildOfAnyType(starArgument, PyListLiteralExpression.class, PyParenthesizedExpression.class,
|
||||
PyStringLiteralExpression.class));
|
||||
final PyExpression expr =
|
||||
PyPsiUtils.flattenParens(PsiTreeUtil.getChildOfAnyType(starArgument, PyListLiteralExpression.class, PyParenthesizedExpression.class,
|
||||
PyStringLiteralExpression.class));
|
||||
if (expr == null) {
|
||||
return Ref.create(starArgument);
|
||||
}
|
||||
@@ -374,7 +378,10 @@ public class PySubstitutionChunkReference extends PsiReferenceBase<PyStringLiter
|
||||
return resolveDoubleStar(expression, mappingKey, false, allKeysForSure);
|
||||
}
|
||||
|
||||
private @Nullable Ref<PyExpression> resolveDoubleStar(@NotNull PyDictLiteralExpression expression, @NotNull String mappingKey, boolean isNumeric, boolean allKeysForSure) {
|
||||
private @Nullable Ref<PyExpression> resolveDoubleStar(@NotNull PyDictLiteralExpression expression,
|
||||
@NotNull String mappingKey,
|
||||
boolean isNumeric,
|
||||
boolean allKeysForSure) {
|
||||
final LanguageLevel languageLevel = LanguageLevel.forElement(expression);
|
||||
PyDoubleStarExpression[] starExpressions = PsiTreeUtil.getChildrenOfType(expression, PyDoubleStarExpression.class);
|
||||
if (languageLevel.isAtLeast(LanguageLevel.PYTHON35) && starExpressions != null) {
|
||||
@@ -391,7 +398,7 @@ public class PySubstitutionChunkReference extends PsiReferenceBase<PyStringLiter
|
||||
}
|
||||
|
||||
allKeysForSure = element != null;
|
||||
if (element != null && !element.isNull()) return element;
|
||||
if (element != null && !element.isNull()) return element;
|
||||
}
|
||||
else if (underStarExpr instanceof PyCallExpression) {
|
||||
Ref<PyExpression> element = resolveDictCall((PyCallExpression)underStarExpr, mappingKey, true);
|
||||
|
||||
+2
-2
@@ -31,11 +31,11 @@ public final class PyClassInsertHandler implements InsertHandler<LookupElement>
|
||||
PyClass pyClass = PyUtil.as(item.getPsiElement(), PyClass.class);
|
||||
PyFunction init = pyClass != null ? pyClass.findInitOrNew(true, null) : null;
|
||||
if (init != null && PyFunctionInsertHandler.hasParams(context, init)) {
|
||||
editor.getCaretModel().moveToOffset(offset+1);
|
||||
editor.getCaretModel().moveToOffset(offset + 1);
|
||||
AutoPopupController.getInstance(context.getProject()).autoPopupParameterInfo(context.getEditor(), init);
|
||||
}
|
||||
else {
|
||||
editor.getCaretModel().moveToOffset(offset+2);
|
||||
editor.getCaretModel().moveToOffset(offset + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -100,7 +100,7 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val project = originalFile.getProject()
|
||||
val typeEvalContext = TypeEvalContext.codeCompletion(project, originalFile)
|
||||
val maxVariants = intValue("ide.completion.variant.limit")
|
||||
@@ -109,7 +109,7 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
val fileBasedIndex = FileBasedIndex.getInstance()
|
||||
TimeoutUtil.run<RuntimeException>(ThrowableRunnable {
|
||||
val alreadySuggested: MutableSet<QualifiedName> = HashSet()
|
||||
|
||||
|
||||
// Suggest importable modules and packages
|
||||
val modulePackageScope = createScope(originalFile, false)
|
||||
forEachModulePackageNameFromIndex(modulePackageScope) { modulePackageName: String ->
|
||||
@@ -209,7 +209,7 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
private fun getInsertHandler(
|
||||
exported: PyElement,
|
||||
position: PsiElement,
|
||||
typeEvalContext: TypeEvalContext
|
||||
typeEvalContext: TypeEvalContext,
|
||||
): InsertHandler<LookupElement> {
|
||||
if (position.getParent() is PyStringLiteralExpression) {
|
||||
if (isInsideAllInInitPy(position)) {
|
||||
@@ -228,7 +228,7 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
|
||||
private fun containsOnlyElementUnderTheCaret(
|
||||
remainingResults: MutableSet<CompletionResult>,
|
||||
parameters: CompletionParameters
|
||||
parameters: CompletionParameters,
|
||||
): Boolean {
|
||||
val position = parameters.originalPosition
|
||||
if (remainingResults.size == 1 && position != null) {
|
||||
@@ -272,9 +272,9 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
|
||||
private fun isApplicableInInsertionContext(
|
||||
definition: PyElement,
|
||||
fqn: QualifiedName,
|
||||
fqn: QualifiedName,
|
||||
position: PsiElement,
|
||||
context: TypeEvalContext
|
||||
context: TypeEvalContext,
|
||||
): Boolean {
|
||||
if (PyTypingTypeProvider.isInsideTypeHint(position, context)) {
|
||||
// Not all names from typing.py are defined as classes
|
||||
@@ -295,15 +295,15 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
}
|
||||
return element is PyTypeAliasStatement
|
||||
}
|
||||
|
||||
|
||||
private fun isInsideErrorElement(referenceExpression: PyReferenceExpression): Boolean {
|
||||
return referenceExpression.findParentOfType<PsiErrorElement>() != null
|
||||
}
|
||||
|
||||
private fun isInsideImportElement(referenceExpression: PyReferenceExpression): Boolean {
|
||||
return referenceExpression.findParentOfType<PyImportStatementBase>() != null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun isDirectlyInsideClassBody(referenceExpression: PyReferenceExpression): Boolean {
|
||||
return referenceExpression.parent is PyExpressionStatement &&
|
||||
ScopeUtil.getScopeOwner(referenceExpression.parent) is PyClass
|
||||
@@ -403,7 +403,7 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
// See PY-73964, IJPL-265
|
||||
private const val RECURSIVE_INDEX_ACCESS_ALLOWED = false
|
||||
}
|
||||
|
||||
|
||||
object InsertHandlers {
|
||||
internal val importingInsertHandler: InsertHandler<LookupElement> = InsertHandler { context, item ->
|
||||
addImportForLookupElement(context, item, context.tailOffset - 1)
|
||||
@@ -445,7 +445,7 @@ class PyClassNameCompletionContributor : CompletionContributor(), DumbAware {
|
||||
context.document.insertString(context.startOffset, qualifiedNamePrefix)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun addImportForLookupElement(context: InsertionContext, item: LookupElement, tailOffset: Int) {
|
||||
val manager = PsiDocumentManager.getInstance(context.project)
|
||||
val document = manager.getDocument(context.file)
|
||||
|
||||
+25
-15
@@ -60,12 +60,14 @@ fun CompletionParameters.getTypeEvalContext(): TypeEvalContext = TypeEvalContext
|
||||
* @param pyClass if provided will check if method does not exist already
|
||||
* @param builderPostprocessor function to be used to tune lookup builder
|
||||
*/
|
||||
fun addMethodToResult(result: CompletionResultSet,
|
||||
pyClass: PyClass?,
|
||||
typeEvalContext: TypeEvalContext,
|
||||
methodName: String,
|
||||
methodParentheses: String = "(self)",
|
||||
builderPostprocessor: ((LookupElementBuilder) -> LookupElementBuilder)? = null) {
|
||||
fun addMethodToResult(
|
||||
result: CompletionResultSet,
|
||||
pyClass: PyClass?,
|
||||
typeEvalContext: TypeEvalContext,
|
||||
methodName: String,
|
||||
methodParentheses: String = "(self)",
|
||||
builderPostprocessor: ((LookupElementBuilder) -> LookupElementBuilder)? = null,
|
||||
) {
|
||||
if (pyClass?.findMethodByName(methodName, false, typeEvalContext) != null) return
|
||||
|
||||
val item = LookupElementBuilder.create(methodName + methodParentheses).withIcon(
|
||||
@@ -79,11 +81,13 @@ fun addMethodToResult(result: CompletionResultSet,
|
||||
* @param pyFile if provided will check if function does not exist already
|
||||
* @param builderPostprocessor function to be used to tune lookup builder
|
||||
*/
|
||||
fun addFunctionToResult(result: CompletionResultSet,
|
||||
pyFile: PyFile?,
|
||||
functionName: String,
|
||||
functionParentheses: String = "()",
|
||||
builderPostprocessor: ((LookupElementBuilder) -> LookupElementBuilder)? = null) {
|
||||
fun addFunctionToResult(
|
||||
result: CompletionResultSet,
|
||||
pyFile: PyFile?,
|
||||
functionName: String,
|
||||
functionParentheses: String = "()",
|
||||
builderPostprocessor: ((LookupElementBuilder) -> LookupElementBuilder)? = null,
|
||||
) {
|
||||
if (pyFile?.findTopLevelFunction(functionName) != null) return
|
||||
|
||||
val item = LookupElementBuilder.create(functionName + functionParentheses).withIcon(
|
||||
@@ -126,7 +130,13 @@ const val FALLBACK_WEIGHT = -1_000_000
|
||||
* @param completionLocation file, in which the completion is taking place
|
||||
* @param nameOnly indicates that we just need to check the name for underscores
|
||||
*/
|
||||
fun computeCompletionWeight(element: PsiElement, elementName: String?, path: QualifiedName?, completionLocation: PsiFile?, nameOnly: Boolean): Int {
|
||||
fun computeCompletionWeight(
|
||||
element: PsiElement,
|
||||
elementName: String?,
|
||||
path: QualifiedName?,
|
||||
completionLocation: PsiFile?,
|
||||
nameOnly: Boolean,
|
||||
): Int {
|
||||
var weight = 0
|
||||
val name = elementName ?: return FALLBACK_WEIGHT
|
||||
|
||||
@@ -156,18 +166,18 @@ fun computeCompletionWeight(element: PsiElement, elementName: String?, path: Qua
|
||||
weight -= LOCATION_NOT_YET_IMPORTED
|
||||
}
|
||||
|
||||
val privatePathComponents = importPath.components.count{ it.startsWith("_") } * PRIVATE_API
|
||||
val privatePathComponents = importPath.components.count { it.startsWith("_") } * PRIVATE_API
|
||||
weight -= privatePathComponents + importPath.componentCount
|
||||
|
||||
if (vFile != null) {
|
||||
weight -= when {
|
||||
weight -= when {
|
||||
PySkeletonUtil.isStdLib(vFile, sdk) -> LOCATION
|
||||
ModuleUtilCore.findModuleForFile(vFile, element.project) == null -> LOCATION * 2
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
weight -= when(PyUtil.turnInitIntoDir(element)) {
|
||||
weight -= when (PyUtil.turnInitIntoDir(element)) {
|
||||
is PsiDirectory -> ELEMENT_TYPE * 2
|
||||
is PyFile -> ELEMENT_TYPE
|
||||
else -> 0
|
||||
|
||||
+21
-13
@@ -45,9 +45,11 @@ private class DictLiteralCompletionProvider : CompletionProvider<CompletionParam
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCompletionToCallExpression(originalElement: PsiElement,
|
||||
possibleSequenceExpr: PySequenceExpression,
|
||||
result: CompletionResultSet) {
|
||||
private fun addCompletionToCallExpression(
|
||||
originalElement: PsiElement,
|
||||
possibleSequenceExpr: PySequenceExpression,
|
||||
result: CompletionResultSet,
|
||||
) {
|
||||
val typeEvalContext = TypeEvalContext.codeCompletion(originalElement.project, originalElement.containingFile)
|
||||
val quote = getForcedQuote(possibleSequenceExpr, originalElement)
|
||||
possibleSequenceExpr.getMappedParameters(PyResolveContext.defaultContext(typeEvalContext))?.forEach {
|
||||
@@ -67,9 +69,11 @@ private class DictLiteralCompletionProvider : CompletionProvider<CompletionParam
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun addCompletionToAssignment(originalElement: PsiElement,
|
||||
possibleSequenceExpr: PySequenceExpression,
|
||||
result: CompletionResultSet) {
|
||||
private fun addCompletionToAssignment(
|
||||
originalElement: PsiElement,
|
||||
possibleSequenceExpr: PySequenceExpression,
|
||||
result: CompletionResultSet,
|
||||
) {
|
||||
val assignment = PsiTreeUtil.getParentOfType(originalElement, PyAssignmentStatement::class.java)
|
||||
if (assignment != null) {
|
||||
val typeEvalContext = TypeEvalContext.codeCompletion(originalElement.project, originalElement.containingFile)
|
||||
@@ -97,9 +101,11 @@ private class DictLiteralCompletionProvider : CompletionProvider<CompletionParam
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCompletionToReturnStatement(originalElement: PsiElement,
|
||||
possibleSequenceExpr: PySequenceExpression,
|
||||
result: CompletionResultSet) {
|
||||
private fun addCompletionToReturnStatement(
|
||||
originalElement: PsiElement,
|
||||
possibleSequenceExpr: PySequenceExpression,
|
||||
result: CompletionResultSet,
|
||||
) {
|
||||
val returnStatement = PsiTreeUtil.getParentOfType(originalElement, PyReturnStatement::class.java)
|
||||
if (returnStatement != null) {
|
||||
val typeEvalContext = TypeEvalContext.codeCompletion(originalElement.project, originalElement.containingFile)
|
||||
@@ -115,10 +121,12 @@ private class DictLiteralCompletionProvider : CompletionProvider<CompletionParam
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCompletionForTypedDictKeys(expectedType: PyType?,
|
||||
expression: PyExpression,
|
||||
dictCompletion: CompletionResultSet,
|
||||
quote: String) {
|
||||
private fun addCompletionForTypedDictKeys(
|
||||
expectedType: PyType?,
|
||||
expression: PyExpression,
|
||||
dictCompletion: CompletionResultSet,
|
||||
quote: String,
|
||||
) {
|
||||
if (expectedType is PyTypedDictType) {
|
||||
val keys = when (expression) {
|
||||
is PyDictLiteralExpression -> expression.elements
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ public final class PyDocstringCompletionContributor extends CompletionContributo
|
||||
}
|
||||
final String text = file.getText();
|
||||
StringBuilder prefixBuilder = new StringBuilder();
|
||||
while(offset > 0 && Character.isLetterOrDigit(text.charAt(offset))) {
|
||||
while (offset > 0 && Character.isLetterOrDigit(text.charAt(offset))) {
|
||||
prefixBuilder.insert(0, text.charAt(offset));
|
||||
offset--;
|
||||
}
|
||||
|
||||
+97
-92
@@ -77,7 +77,9 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
PsiElement prev = p.getPrevSibling();
|
||||
while (prev instanceof PsiWhiteSpace) prev = prev.getPrevSibling();
|
||||
if (prev == null) return true; // there was only whitespace before us
|
||||
if (prev instanceof PyStatement || prev instanceof PsiComment || prev instanceof OuterLanguageElement) { // a non-stmt would be something strange
|
||||
if (prev instanceof PyStatement ||
|
||||
prev instanceof PsiComment ||
|
||||
prev instanceof OuterLanguageElement) { // a non-stmt would be something strange
|
||||
if (prev.getLastChild() instanceof PsiErrorElement) {
|
||||
// prev stmt ends with an error. are we on the same line?
|
||||
PsiDocumentManager docMgr = PsiDocumentManager.getInstance(p.getProject());
|
||||
@@ -240,8 +242,9 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
psiElement().inFile(psiFile(PyDocstringFile.class)));
|
||||
|
||||
private static final ElementPattern<PsiElement> IN_FUNCTION_HEADER =
|
||||
psiElement().inside(PyFunction.class).andNot(or(psiElement().inside(false, psiElement(PyStatementList.class), psiElement(PyFunction.class)),
|
||||
psiElement().inside(false, psiElement(PyParameterList.class), psiElement(PyFunction.class))));
|
||||
psiElement().inside(PyFunction.class)
|
||||
.andNot(or(psiElement().inside(false, psiElement(PyStatementList.class), psiElement(PyFunction.class)),
|
||||
psiElement().inside(false, psiElement(PyParameterList.class), psiElement(PyFunction.class))));
|
||||
|
||||
public static final PsiElementPattern.Capture<PsiElement> AFTER_QUALIFIER =
|
||||
psiElement().afterLeaf(psiElement().withText(".").inside(PyReferenceExpression.class));
|
||||
@@ -307,7 +310,8 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
|
||||
private static final PsiElementPattern.Capture<PsiElement> IN_PARAM_LIST = psiElement().inside(PyParameterList.class);
|
||||
private static final PsiElementPattern.Capture<PsiElement> IN_ARG_LIST = psiElement().inside(PyArgumentList.class);
|
||||
private static final PsiElementPattern.Capture<PsiElement> IN_DECORATOR_ARG_LIST = psiElement().inside(PyArgumentList.class).inside(PyDecorator.class);
|
||||
private static final PsiElementPattern.Capture<PsiElement> IN_DECORATOR_ARG_LIST =
|
||||
psiElement().inside(PyArgumentList.class).inside(PyDecorator.class);
|
||||
|
||||
private static final PsiElementPattern.Capture<PsiElement> IN_DEF_BODY =
|
||||
psiElement().inside(false, psiElement(PyFunction.class), psiElement(PyClass.class));
|
||||
@@ -338,7 +342,7 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
|
||||
private static final PsiElementPattern.Capture<PsiElement> AFTER_COND_STMT_NO_ELSE =
|
||||
afterStatement(psiElement().withChild(psiElement(PyConditionalStatementPart.class))
|
||||
.withLastChild(not(psiElement(PyElsePart.class))));
|
||||
.withLastChild(not(psiElement(PyElsePart.class))));
|
||||
|
||||
private static <T extends PsiElement> PsiElementPattern.Capture<PsiElement> afterStatement(final PsiElementPattern.Capture<T> statementPattern) {
|
||||
return psiElement().atStartOf(psiElement(PyExpressionStatement.class)
|
||||
@@ -372,7 +376,8 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
));
|
||||
*/
|
||||
|
||||
private static final FilterPattern PY3K = new FilterPattern(new PyKeywordCompletionContributor.LanguageLevelAtLeastFilter(LanguageLevel.PYTHON30));
|
||||
private static final FilterPattern PY3K =
|
||||
new FilterPattern(new PyKeywordCompletionContributor.LanguageLevelAtLeastFilter(LanguageLevel.PYTHON30));
|
||||
private static final FilterPattern PY35 = new FilterPattern(new LanguageLevelAtLeastFilter(LanguageLevel.PYTHON35));
|
||||
private static final FilterPattern PY310 = new FilterPattern(new LanguageLevelAtLeastFilter(LanguageLevel.PYTHON310));
|
||||
|
||||
@@ -458,7 +463,8 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
final @NotNull ProcessingContext context,
|
||||
final @NotNull CompletionResultSet result
|
||||
) {
|
||||
putKeywords(result, TailTypes.spaceType(), PyNames.ASSERT, PyNames.DEL, PyNames.EXEC, PyNames.FROM, PyNames.IMPORT, PyNames.RAISE);
|
||||
putKeywords(result, TailTypes.spaceType(), PyNames.ASSERT, PyNames.DEL, PyNames.EXEC, PyNames.FROM, PyNames.IMPORT,
|
||||
PyNames.RAISE);
|
||||
putKeywords(result, TailTypes.noneType(), PyNames.PASS);
|
||||
}
|
||||
}
|
||||
@@ -470,12 +476,12 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addBreak() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_BEGIN_STMT)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(IN_ARG_LIST)
|
||||
.and(IN_LOOP)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_BEGIN_STMT)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(IN_ARG_LIST)
|
||||
.and(IN_LOOP)
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailTypes.noneType(), PyNames.BREAK)
|
||||
);
|
||||
@@ -484,13 +490,13 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addContinue() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_BEGIN_STMT)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(IN_ARG_LIST)
|
||||
.andOr(not(IN_FINALLY_NO_LOOP), new FilterPattern(new LanguageLevelAtLeastFilter(LanguageLevel.PYTHON38)))
|
||||
.and(IN_LOOP)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_BEGIN_STMT)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(IN_ARG_LIST)
|
||||
.andOr(not(IN_FINALLY_NO_LOOP), new FilterPattern(new LanguageLevelAtLeastFilter(LanguageLevel.PYTHON38)))
|
||||
.and(IN_LOOP)
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailTypes.noneType(), PyNames.CONTINUE)
|
||||
);
|
||||
@@ -509,21 +515,21 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addWithinFuncs() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_DEF_BODY)
|
||||
.and(IN_BEGIN_STMT)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_DEF_BODY)
|
||||
.and(IN_BEGIN_STMT)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
,
|
||||
new PyKeywordCompletionProvider(PyNames.GLOBAL, PyNames.RETURN, PyNames.YIELD)
|
||||
);
|
||||
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_DEF_BODY)
|
||||
.and(IN_BEGIN_STMT)
|
||||
.and(PY3K)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_DEF_BODY)
|
||||
.and(IN_BEGIN_STMT)
|
||||
.and(PY3K)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
,
|
||||
new PyKeywordCompletionProvider(PyNames.NONLOCAL)
|
||||
);
|
||||
@@ -554,10 +560,10 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addWithinIf() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_IF_BODY, AFTER_IF)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_IF_BODY, AFTER_IF)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailTypes.noneType(), PyUnindentingInsertHandler.INSTANCE, PyNames.ELIF));
|
||||
}
|
||||
@@ -565,12 +571,12 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addWithinTry() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_TRY_BODY, IN_EXCEPT_BODY, AFTER_TRY, IN_ELSE_BODY_OF_TRY)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_TRY_BODY, IN_EXCEPT_BODY, AFTER_TRY, IN_ELSE_BODY_OF_TRY)
|
||||
//.andNot(RIGHT_AFTER_COLON)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.andNot(AFTER_FINALLY)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.andNot(AFTER_FINALLY)
|
||||
,
|
||||
new CompletionProvider<>() {
|
||||
@Override
|
||||
@@ -585,12 +591,12 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
);
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_TRY_BODY, IN_EXCEPT_BODY, AFTER_TRY, IN_ELSE_BODY_OF_TRY)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_TRY_BODY, IN_EXCEPT_BODY, AFTER_TRY, IN_ELSE_BODY_OF_TRY)
|
||||
//.andNot(RIGHT_AFTER_COLON)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.andNot(AFTER_FINALLY).andNot(AFTER_ELSE)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.andNot(AFTER_FINALLY).andNot(AFTER_ELSE)
|
||||
,
|
||||
new CompletionProvider<>() {
|
||||
@Override
|
||||
@@ -608,10 +614,10 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addElse() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_COND_STMT, IN_EXCEPT_BODY, AFTER_COND_STMT_NO_ELSE, AFTER_LOOP_NO_ELSE, AFTER_EXCEPT)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(FIRST_ON_LINE)
|
||||
.andOr(IN_COND_STMT, IN_EXCEPT_BODY, AFTER_COND_STMT_NO_ELSE, AFTER_LOOP_NO_ELSE, AFTER_EXCEPT)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailTypes.caseColonType(), PyUnindentingInsertHandler.INSTANCE, PyNames.ELSE));
|
||||
}
|
||||
@@ -619,12 +625,12 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addInfixOperators() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(BEFORE_COND)
|
||||
.andNot(IN_IMPORT_STMT) // expressions there are not logical anyway
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(AFTER_QUALIFIER).
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(BEFORE_COND)
|
||||
.andNot(IN_IMPORT_STMT) // expressions there are not logical anyway
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(AFTER_QUALIFIER).
|
||||
andNot(IN_STRING_LITERAL).and(IN_BEGIN_STMT)
|
||||
,
|
||||
new PyKeywordCompletionProvider(PyNames.AND, PyNames.OR, PyNames.IS, PyNames.IN)
|
||||
@@ -634,14 +640,14 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addNot() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(IN_IMPORT_STMT)
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(IN_FUNCTION_HEADER)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL).andNot(TARGET_AFTER_QUALIFIER)
|
||||
.andNot(IN_PATTERN)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(IN_IMPORT_STMT)
|
||||
.andNot(IN_PARAM_LIST)
|
||||
.andNot(IN_FUNCTION_HEADER)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
|
||||
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL).andNot(TARGET_AFTER_QUALIFIER)
|
||||
.andNot(IN_PATTERN)
|
||||
,
|
||||
new PyKeywordCompletionProvider(PyNames.NOT, PyNames.LAMBDA)
|
||||
);
|
||||
@@ -651,24 +657,24 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
// Add literals in normal contexts
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(IN_IMPORT_STMT)
|
||||
.and(NOT_PARAMETER_OR_DEFAULT_VALUE)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_FUNCTION_HEADER)
|
||||
.andNot(IN_STRING_LITERAL)
|
||||
.andNot(TARGET_AFTER_QUALIFIER)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(IN_IMPORT_STMT)
|
||||
.and(NOT_PARAMETER_OR_DEFAULT_VALUE)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_FUNCTION_HEADER)
|
||||
.andNot(IN_STRING_LITERAL)
|
||||
.andNot(TARGET_AFTER_QUALIFIER)
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailTypes.noneType(), PyNames.TRUE, PyNames.FALSE, PyNames.NONE));
|
||||
|
||||
// Add literals specifically in decorator argument lists
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_DECORATOR_ARG_LIST)
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(IN_STRING_LITERAL)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_DECORATOR_ARG_LIST)
|
||||
.andNot(IN_COMMENT)
|
||||
.andNot(IN_STRING_LITERAL)
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailTypes.noneType(), PyNames.TRUE, PyNames.FALSE, PyNames.NONE));
|
||||
extend(CompletionType.BASIC,
|
||||
@@ -714,10 +720,10 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addAs() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andOr(IN_IMPORT_AFTER_REF, IN_WITH_AFTER_REF, IN_EXCEPT_AFTER_REF)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_COMMENT)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.andOr(IN_IMPORT_AFTER_REF, IN_WITH_AFTER_REF, IN_EXCEPT_AFTER_REF)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.andNot(IN_COMMENT)
|
||||
,
|
||||
new PyKeywordCompletionProvider(PyNames.AS)
|
||||
);
|
||||
@@ -726,9 +732,9 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addImportInFrom() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_FROM_IMPORT_AFTER_REF)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(IN_FROM_IMPORT_AFTER_REF)
|
||||
.andNot(AFTER_QUALIFIER)
|
||||
,
|
||||
new PyKeywordCompletionProvider(PyNames.IMPORT)
|
||||
);
|
||||
@@ -763,10 +769,10 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addExprElse() {
|
||||
extend(
|
||||
CompletionType.BASIC, psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.afterLeafSkipping(psiElement().whitespace(),
|
||||
psiElement().inside(psiElement(PyConditionalExpression.class))
|
||||
.and(psiElement().afterLeaf(PyNames.IF)))
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.afterLeafSkipping(psiElement().whitespace(),
|
||||
psiElement().inside(psiElement(PyConditionalExpression.class))
|
||||
.and(psiElement().afterLeaf(PyNames.IF)))
|
||||
,
|
||||
new PyKeywordCompletionProvider(TailTypes.spaceType(), PyNames.ELSE));
|
||||
}
|
||||
@@ -792,8 +798,8 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
.afterLeaf(psiElement().withElementType(PyTokenTypes.AUG_ASSIGN_OPERATIONS)),
|
||||
psiElement()
|
||||
.inside(true, psiElement(PyParenthesizedExpression.class)))
|
||||
.andNot(IN_STRING_LITERAL)
|
||||
.andNot(IN_COMMENT),
|
||||
.andNot(IN_STRING_LITERAL)
|
||||
.andNot(IN_COMMENT),
|
||||
new PyKeywordCompletionProvider(PyNames.YIELD));
|
||||
}
|
||||
|
||||
@@ -834,11 +840,11 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
private void addForToComprehensions() {
|
||||
extend(CompletionType.BASIC,
|
||||
psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.inside(psiElement(PySequenceExpression.class))
|
||||
.andNot(psiElement()
|
||||
.afterLeaf(or(psiElement(PyTokenTypes.LBRACE), psiElement(PyTokenTypes.LBRACKET), psiElement(PyTokenTypes.LPAR))))
|
||||
.andNot(IN_COMMENT),
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.inside(psiElement(PySequenceExpression.class))
|
||||
.andNot(psiElement()
|
||||
.afterLeaf(or(psiElement(PyTokenTypes.LBRACE), psiElement(PyTokenTypes.LBRACKET), psiElement(PyTokenTypes.LPAR))))
|
||||
.andNot(IN_COMMENT),
|
||||
new PyKeywordCompletionProvider(PyNames.FOR));
|
||||
}
|
||||
|
||||
@@ -848,7 +854,6 @@ public final class PyKeywordCompletionContributor extends CompletionContributor
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.and(psiElement()).afterLeaf(psiElement().afterLeaf(PyNames.FOR)),
|
||||
new PyKeywordCompletionProvider(PyNames.IN));
|
||||
|
||||
}
|
||||
|
||||
private static final class PyKeywordCompletionProvider extends CompletionProvider<CompletionParameters> {
|
||||
|
||||
+4
-4
@@ -47,10 +47,10 @@ public final class PyMetaClassCompletionContributor extends CompletionContributo
|
||||
});
|
||||
extend(CompletionType.BASIC,
|
||||
PlatformPatterns
|
||||
.psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.withParents(PyReferenceExpression.class, PyArgumentList.class, PyClass.class)
|
||||
.and(hasLanguageLevel(level -> !level.isPython2())),
|
||||
.psiElement()
|
||||
.withLanguage(PythonLanguage.getInstance())
|
||||
.withParents(PyReferenceExpression.class, PyArgumentList.class, PyClass.class)
|
||||
.and(hasLanguageLevel(level -> !level.isPython2())),
|
||||
new CompletionProvider<>() {
|
||||
@Override
|
||||
protected void addCompletions(@NotNull CompletionParameters parameters,
|
||||
|
||||
+6
-5
@@ -21,7 +21,7 @@ import com.jetbrains.python.psi.impl.PyPsiUtils
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext
|
||||
import com.jetbrains.python.psi.types.PyCallableParameter
|
||||
|
||||
class PyMultipleArgumentsCompletionContributor: CompletionContributor(), DumbAware {
|
||||
class PyMultipleArgumentsCompletionContributor : CompletionContributor(), DumbAware {
|
||||
init {
|
||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inArgumentList(), MyCompletionProvider)
|
||||
}
|
||||
@@ -45,8 +45,9 @@ class PyMultipleArgumentsCompletionContributor: CompletionContributor(), DumbAwa
|
||||
val argumentIndex = callableType.implicitOffset + argumentExplicitIndex
|
||||
if (callableParameters == null ||
|
||||
argumentIndex >= callableParameters.size ||
|
||||
callableParameters.any { it.isKeywordContainer || it.isPositionalContainer }) {
|
||||
return@forEach
|
||||
callableParameters.any { it.isKeywordContainer || it.isPositionalContainer }
|
||||
) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val unfilledParameters = ContainerUtil.subList(callableParameters, argumentIndex)
|
||||
@@ -110,7 +111,7 @@ class PyMultipleArgumentsCompletionContributor: CompletionContributor(), DumbAwa
|
||||
ControlFlowCache.getScope(scope).namedElements
|
||||
.asSequence()
|
||||
.filter { element ->
|
||||
PsiTreeUtil.getParentOfType(element, PyListCompExpression::class.java) ?.let { listComp ->
|
||||
PsiTreeUtil.getParentOfType(element, PyListCompExpression::class.java)?.let { listComp ->
|
||||
PsiTreeUtil.isAncestor(listComp.resultExpression, position, false)
|
||||
} ?: PyPsiUtils.isBefore(element, position)
|
||||
}
|
||||
@@ -119,7 +120,7 @@ class PyMultipleArgumentsCompletionContributor: CompletionContributor(), DumbAwa
|
||||
}
|
||||
}
|
||||
|
||||
class PyMultipleArgumentsInsertHandler(private val call: PyCallExpression): ParenthesesInsertHandler<LookupElement>() {
|
||||
class PyMultipleArgumentsInsertHandler(private val call: PyCallExpression) : ParenthesesInsertHandler<LookupElement>() {
|
||||
override fun placeCaretInsideParentheses(context: InsertionContext?, item: LookupElement?): Boolean = false
|
||||
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
|
||||
+2
-2
@@ -298,7 +298,7 @@ public final class PyStringFormatCompletionContributor extends CompletionContrib
|
||||
private static @NotNull List<LookupElement> getElementsFromDict(final @NotNull PyDictLiteralExpression dict) {
|
||||
return Arrays.stream(dict.getElements())
|
||||
.map(e -> PyUtil.as(e.getKey(), PyStringLiteralExpression.class))
|
||||
.filter(k-> k != null)
|
||||
.filter(k -> k != null)
|
||||
.map(k -> createLookUpElement(k.getStringValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@@ -317,7 +317,7 @@ public final class PyStringFormatCompletionContributor extends CompletionContrib
|
||||
|
||||
private static @Nullable LookupElement getKeywordArgument(final @NotNull PyKeywordArgument arg) {
|
||||
final String keyword = arg.getKeyword();
|
||||
return keyword != null ? createLookUpElement(keyword) : null;
|
||||
return keyword != null ? createLookUpElement(keyword) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -146,8 +146,8 @@ public final class PyStructuralTypeAttributesCompletionContributor extends Compl
|
||||
* intermediate results in case of a large class hierarchy.
|
||||
*/
|
||||
private static @NotNull Set<PyClass> getAncestorClassesFast(@NotNull PyClass pyClass,
|
||||
@NotNull TypeEvalContext context,
|
||||
@NotNull Map<PyClass, Set<PyClass>> ancestorsCache) {
|
||||
@NotNull TypeEvalContext context,
|
||||
@NotNull Map<PyClass, Set<PyClass>> ancestorsCache) {
|
||||
final Set<PyClass> ancestors = ancestorsCache.get(pyClass);
|
||||
if (ancestors != null) {
|
||||
return ancestors;
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ class PyUnresolvedModuleAttributeCompletionContributor : CompletionContributor()
|
||||
.filterIsInstance<PyFile>()
|
||||
.map { PyModuleType(it) }
|
||||
.flatMap { it.getCompletionVariantsAsLookupElements(parameters.position, context, false, false, typeContext) }
|
||||
.filter { PyNames.isIdentifier(it.lookupString) && !it.lookupString.startsWith('_')}
|
||||
.filter { PyNames.isIdentifier(it.lookupString) && !it.lookupString.startsWith('_') }
|
||||
.filter { attribute.isEmpty() || resultMatchingCompleteReference.prefixMatcher.prefixMatches("$qualifier.${it.lookupString}") }
|
||||
.mapNotNull {
|
||||
val element = it.psiElement as? PyElement
|
||||
|
||||
+1
-2
@@ -15,7 +15,7 @@ import javax.swing.*;
|
||||
/**
|
||||
* TODO: Add description
|
||||
*/
|
||||
public class PythonLookupElement extends LookupElement implements Comparable<LookupElement>{
|
||||
public class PythonLookupElement extends LookupElement implements Comparable<LookupElement> {
|
||||
|
||||
protected final String myLookupString;
|
||||
protected final String myTypeText;
|
||||
@@ -100,6 +100,5 @@ public class PythonLookupElement extends LookupElement implements Comparable<Loo
|
||||
public int compareTo(final LookupElement o) {
|
||||
return myLookupString.compareTo(o.getLookupString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -27,7 +27,8 @@ import static com.intellij.reference.SoftReference.dereference;
|
||||
|
||||
|
||||
public final class ControlFlowCache {
|
||||
private static final Key<SoftReference<PyControlFlow>> CONTROL_FLOW_KEY = Key.create("com.jetbrains.python.codeInsight.controlflow.ControlFlow");
|
||||
private static final Key<SoftReference<PyControlFlow>> CONTROL_FLOW_KEY =
|
||||
Key.create("com.jetbrains.python.codeInsight.controlflow.ControlFlow");
|
||||
private static final Key<SoftReference<Scope>> SCOPE_KEY = Key.create("com.jetbrains.python.codeInsight.controlflow.Scope");
|
||||
|
||||
private ControlFlowCache() {
|
||||
|
||||
+11
-10
@@ -45,11 +45,12 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
private final ControlFlowBuilder myBuilder = new ControlFlowBuilder();
|
||||
|
||||
private @Nullable TrueFalseNodes myTrueFalseNodes;
|
||||
|
||||
|
||||
// see com.jetbrains.python.PyPatternTypeTest.testMatchClassPatternShadowingCapture
|
||||
private final @NotNull List<String> myPatternBindingNames = new ArrayList<>();
|
||||
|
||||
private record TrueFalseNodes(@NotNull Instruction trueNode, @NotNull Instruction falseNode) {}
|
||||
private record TrueFalseNodes(@NotNull Instruction trueNode, @NotNull Instruction falseNode) {
|
||||
}
|
||||
|
||||
public PyControlFlow buildControlFlow(final @NotNull ScopeOwner owner) {
|
||||
return new PyControlFlow(myBuilder.build(this, owner));
|
||||
@@ -346,15 +347,15 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
for (PyCaseClause clause : matchStatement.getCaseClauses()) {
|
||||
myBuilder.prevInstruction = nextClause;
|
||||
nextClause = addTransparentInstruction();
|
||||
|
||||
|
||||
myPatternBindingNames.clear();
|
||||
|
||||
|
||||
PyPattern pattern = clause.getPattern();
|
||||
if (pattern != null) {
|
||||
pattern.accept(this);
|
||||
addTypeAssertionNodes(clause, true, myPatternBindingNames);
|
||||
}
|
||||
|
||||
|
||||
PyExpression guard = clause.getGuardCondition();
|
||||
if (guard != null) {
|
||||
TransparentInstruction trueNode = addTransparentInstruction();
|
||||
@@ -650,7 +651,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
elsePart.accept(this);
|
||||
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
|
||||
}
|
||||
|
||||
|
||||
|
||||
myBuilder.flowAbrupted();
|
||||
collectInternalPendingEdges(node);
|
||||
@@ -958,7 +959,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
myBuilder.addEdge(myBuilder.prevInstruction, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
collectInternalPendingEdges(node);
|
||||
}
|
||||
|
||||
@@ -1147,7 +1148,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
private TransparentInstruction addTransparentInstruction() {
|
||||
return addTransparentInstruction(null);
|
||||
}
|
||||
|
||||
|
||||
private TransparentInstruction addTransparentInstruction(@Nullable PsiElement element) {
|
||||
TransparentInstructionImpl instruction = new TransparentInstructionImpl(myBuilder, element, "");
|
||||
myBuilder.instructions.add(instruction);
|
||||
@@ -1162,11 +1163,11 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to collect all pending edges
|
||||
* Can be used to collect all pending edges
|
||||
* that we used to build CFG for `node`,
|
||||
* but are not relevant to other elements.
|
||||
* Is almost equivalent to this:
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
* visitPy...(node);
|
||||
* myBuilder.startNode(node.nextSibling); // collectInternalPendingEdges does this, without needing nextSibling
|
||||
|
||||
+4
-3
@@ -6,9 +6,10 @@ import com.jetbrains.python.psi.PyAssertStatement
|
||||
import com.jetbrains.python.psi.PyRaiseStatement
|
||||
import com.jetbrains.python.psi.PyStatement
|
||||
|
||||
class PyRaiseInstruction private constructor(builder: ControlFlowBuilder, raiseOrAssert: PyStatement): InstructionImpl(builder, raiseOrAssert) {
|
||||
constructor(builder: ControlFlowBuilder, raise: PyRaiseStatement): this(builder, raise as PyStatement)
|
||||
constructor(builder: ControlFlowBuilder, assert: PyAssertStatement): this(builder, assert as PyStatement)
|
||||
class PyRaiseInstruction private constructor(builder: ControlFlowBuilder, raiseOrAssert: PyStatement) : InstructionImpl(builder,
|
||||
raiseOrAssert) {
|
||||
constructor(builder: ControlFlowBuilder, raise: PyRaiseStatement) : this(builder, raise as PyStatement)
|
||||
constructor(builder: ControlFlowBuilder, assert: PyAssertStatement) : this(builder, assert as PyStatement)
|
||||
|
||||
override fun getElementPresentation(): String = "raise: ${element}"
|
||||
}
|
||||
+18
-9
@@ -131,7 +131,8 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
PyExpression[] elements = ((PySequenceExpression)rhs).getElements();
|
||||
List<PyType> types = new ArrayList<>(elements.length);
|
||||
for (PyExpression element : elements) {
|
||||
PyType type = PyLiteralType.isNone(element) ? PyBuiltinCache.getInstance(element).getNoneType() : getLiteralType(element, context);
|
||||
PyType type =
|
||||
PyLiteralType.isNone(element) ? PyBuiltinCache.getInstance(element).getNoneType() : getLiteralType(element, context);
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -201,7 +202,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
public static @Nullable Ref<PyType> createAssertionType(@Nullable PyType initial,
|
||||
@Nullable PyType suggested,
|
||||
boolean positive,
|
||||
boolean forceStrictNarrow,
|
||||
boolean forceStrictNarrow,
|
||||
@NotNull TypeEvalContext context) {
|
||||
if (suggested == null) return null;
|
||||
if (positive) {
|
||||
@@ -281,7 +282,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static @Nullable PyType intersect(@Nullable PyType initial, @Nullable PyType suggested) {
|
||||
// TODO: if we had IntersectionType, here it would be created. Also, final classes can be handled here
|
||||
if (initial instanceof PyNeverType) {
|
||||
@@ -301,7 +302,9 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
/**
|
||||
* @param transformToDefinition if true the result type will be Type[T], not T itself.
|
||||
*/
|
||||
private static @Nullable PyType transformTypeFromAssertion(@Nullable PyType type, boolean transformToDefinition, @NotNull TypeEvalContext context,
|
||||
private static @Nullable PyType transformTypeFromAssertion(@Nullable PyType type,
|
||||
boolean transformToDefinition,
|
||||
@NotNull TypeEvalContext context,
|
||||
@Nullable PyExpression typeElement) {
|
||||
/*
|
||||
* We need to distinguish:
|
||||
@@ -348,7 +351,11 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
pushAssertion(expr, positive, false, isStrictNarrowingAllowed(), suggestedType);
|
||||
}
|
||||
|
||||
private void pushAssertion(@Nullable PyExpression expr, boolean positive, boolean allowAnyExpr, boolean forceStrictNarrow, @NotNull Function<TypeEvalContext, PyType> suggestedType) {
|
||||
private void pushAssertion(@Nullable PyExpression expr,
|
||||
boolean positive,
|
||||
boolean allowAnyExpr,
|
||||
boolean forceStrictNarrow,
|
||||
@NotNull Function<TypeEvalContext, PyType> suggestedType) {
|
||||
expr = PyPsiUtils.flattenParens(expr);
|
||||
if (expr instanceof PySequenceExpression seqExpr) {
|
||||
PyExpression[] elements = seqExpr.getElements();
|
||||
@@ -388,11 +395,11 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static @Nullable PsiElement skipNotAndParens(@Nullable PsiElement element) {
|
||||
if (element == null) return null;
|
||||
for (PsiElement e = element.getParent(); e != null; e = e.getParent()) {
|
||||
if (!(e instanceof PyParenthesizedExpression) &&
|
||||
if (!(e instanceof PyParenthesizedExpression) &&
|
||||
!(e instanceof PyPrefixExpression prefixExpr && prefixExpr.getOperator() == PyTokenTypes.NOT_KEYWORD)) {
|
||||
return e;
|
||||
}
|
||||
@@ -406,8 +413,10 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
if (parent instanceof PyConditionalExpression cond && PsiTreeUtil.isAncestor(cond.getCondition(), node, false)) return true;
|
||||
if (parent instanceof PyBinaryExpression binExpr && (binExpr.isOperator(PyNames.AND) || binExpr.isOperator(PyNames.OR))) return true;
|
||||
if (parent instanceof PyAssertStatement) return true;
|
||||
if (parent instanceof PyGeneratorExpression gen &&
|
||||
ContainerUtil.or(gen.getIfComponents(), it -> PsiTreeUtil.isAncestor(it.getTest(), node, false))) return true;
|
||||
if (parent instanceof PyGeneratorExpression gen &&
|
||||
ContainerUtil.or(gen.getIfComponents(), it -> PsiTreeUtil.isAncestor(it.getTest(), node, false))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -100,7 +100,7 @@ public final class ReadWriteInstruction extends InstructionImpl {
|
||||
public @NotNull ACCESS getAccess() {
|
||||
return myAccess;
|
||||
}
|
||||
|
||||
|
||||
public static @NotNull ReadWriteInstruction read(final @NotNull ControlFlowBuilder builder,
|
||||
final @Nullable PyElement element,
|
||||
final @Nullable String name) {
|
||||
@@ -112,14 +112,14 @@ public final class ReadWriteInstruction extends InstructionImpl {
|
||||
final @Nullable String name) {
|
||||
return new ReadWriteInstruction(builder, element, name, ACCESS.WRITE);
|
||||
}
|
||||
|
||||
|
||||
public static @NotNull ReadWriteInstruction newInstruction(final @NotNull ControlFlowBuilder builder,
|
||||
final @Nullable PsiElement element,
|
||||
final @Nullable String name,
|
||||
final @NotNull ACCESS access) {
|
||||
return new ReadWriteInstruction(builder, element, name, access);
|
||||
}
|
||||
|
||||
|
||||
public static @NotNull ReadWriteInstruction assertType(final @NotNull ControlFlowBuilder builder,
|
||||
final @Nullable PsiElement element,
|
||||
final @Nullable String name,
|
||||
|
||||
+9
-8
@@ -32,9 +32,9 @@ public class PyReachingDefsDfaInstance implements DfaMapInstance<ScopeVariable>
|
||||
|
||||
@Override
|
||||
public DFAMap<ScopeVariable> fun(final DFAMap<ScopeVariable> map, final Instruction instruction) {
|
||||
if (map == UNREACHABLE_MARKER) return map;
|
||||
if (map == UNREACHABLE_MARKER) return map;
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (element == null || ((PyFile) element.getContainingFile()).getLanguageLevel().isPython2()){
|
||||
if (element == null || ((PyFile)element.getContainingFile()).getLanguageLevel().isPython2()) {
|
||||
return processReducedMap(map, instruction, element);
|
||||
}
|
||||
if (PyDataFlowKt.isUnreachableForInspection(element, myContext)) {
|
||||
@@ -50,11 +50,11 @@ public class PyReachingDefsDfaInstance implements DfaMapInstance<ScopeVariable>
|
||||
for (Map.Entry<String, ScopeVariable> entry : map.entrySet()) {
|
||||
final ScopeVariable value = entry.getValue();
|
||||
// Support PEP-3110. (PY-1408)
|
||||
if (value.isParameter()){
|
||||
if (value.isParameter()) {
|
||||
final PsiElement declaration = value.getDeclarations().iterator().next();
|
||||
final PyExceptPart exceptPart = PyExceptPartNavigator.getPyExceptPartByTarget(declaration);
|
||||
if (exceptPart != null){
|
||||
if (!PsiTreeUtil.isAncestor(exceptPart, element, false)){
|
||||
if (exceptPart != null) {
|
||||
if (!PsiTreeUtil.isAncestor(exceptPart, element, false)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -85,10 +85,10 @@ public class PyReachingDefsDfaInstance implements DfaMapInstance<ScopeVariable>
|
||||
}
|
||||
}
|
||||
// Processing PyFunction
|
||||
else if (element instanceof PyFunction){
|
||||
else if (element instanceof PyFunction) {
|
||||
name = ((PyFunction)element).getName();
|
||||
}
|
||||
if (name == null){
|
||||
if (name == null) {
|
||||
return map;
|
||||
}
|
||||
final ScopeVariable variable = map.get(name);
|
||||
@@ -106,7 +106,8 @@ public class PyReachingDefsDfaInstance implements DfaMapInstance<ScopeVariable>
|
||||
final boolean isParameter = variable != null && variable.isParameter();
|
||||
if (variable == null) {
|
||||
scopeVariable = new ScopeVariableImpl(name, isParameter, element);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
scopeVariable = new ScopeVariableImpl(name, isParameter, variable.getDeclarations());
|
||||
}
|
||||
map = map.asWritable();
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class PyReachingDefsSemilattice implements MapSemilattice<ScopeVariable>
|
||||
return ins.get(0);
|
||||
}
|
||||
|
||||
ins = ins.stream().filter( e -> e != PyReachingDefsDfaInstance.UNREACHABLE_MARKER).toList();
|
||||
ins = ins.stream().filter(e -> e != PyReachingDefsDfaInstance.UNREACHABLE_MARKER).toList();
|
||||
|
||||
final Set<String> resultNames = getResultNames(ins);
|
||||
if (resultNames == null || resultNames.isEmpty()) {
|
||||
|
||||
@@ -43,9 +43,11 @@ public interface Scope {
|
||||
@NotNull TypeEvalContext typeEvalContext) throws DFALimitExceededException;
|
||||
|
||||
boolean hasGlobals();
|
||||
|
||||
boolean isGlobal(String name);
|
||||
|
||||
boolean hasNonLocals();
|
||||
|
||||
boolean isNonlocal(String name);
|
||||
|
||||
boolean containsDeclaration(String name);
|
||||
|
||||
+6
-6
@@ -35,26 +35,26 @@ public final class ScopeUtil {
|
||||
private ScopeUtil() {
|
||||
}
|
||||
|
||||
public static @Nullable PsiElement getParameterScope(final PsiElement element){
|
||||
if (element instanceof PyNamedParameter){
|
||||
public static @Nullable PsiElement getParameterScope(final PsiElement element) {
|
||||
if (element instanceof PyNamedParameter) {
|
||||
final PyFunction function = getParentOfType(element, PyFunction.class, false);
|
||||
if (function != null){
|
||||
if (function != null) {
|
||||
return function;
|
||||
}
|
||||
}
|
||||
|
||||
final PyExceptPart exceptPart = PyExceptPartNavigator.getPyExceptPartByTarget(element);
|
||||
if (exceptPart != null){
|
||||
if (exceptPart != null) {
|
||||
return exceptPart;
|
||||
}
|
||||
|
||||
final PyForStatement forStatement = PyForStatementNavigator.getPyForStatementByIterable(element);
|
||||
if (forStatement != null){
|
||||
if (forStatement != null) {
|
||||
return forStatement;
|
||||
}
|
||||
|
||||
final PyListCompExpression listCompExpression = PyListCompExpressionNavigator.getPyListCompExpressionByVariable(element);
|
||||
if (listCompExpression != null){
|
||||
if (listCompExpression != null) {
|
||||
return listCompExpression;
|
||||
}
|
||||
return null;
|
||||
|
||||
+4
-4
@@ -232,10 +232,10 @@ public class ScopeImpl implements Scope {
|
||||
importStmt.accept(new PyVersionAwareElementVisitor(languageLevel) {
|
||||
@Override
|
||||
public void visitPyElement(@NotNull PyElement node) {
|
||||
if (node instanceof PyImportedNameDefiner definer) {
|
||||
importedNameDefiners.add(definer);
|
||||
}
|
||||
super.visitPyElement(node);
|
||||
if (node instanceof PyImportedNameDefiner definer) {
|
||||
importedNameDefiners.add(definer);
|
||||
}
|
||||
super.visitPyElement(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public class ScopeVariableImpl implements ScopeVariable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (isParameter() ? "par" : "var") + "(" + myName+ ")[" + myDeclarations.size() + "]";
|
||||
return (isParameter() ? "par" : "var") + "(" + myName + ")[" + myDeclarations.size() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-1
@@ -28,7 +28,9 @@ import static com.jetbrains.python.psi.types.PyTypeUtil.notNullToRef;
|
||||
public final class PyDecoratedFunctionTypeProvider extends PyTypeProviderBase {
|
||||
|
||||
@Override
|
||||
public @Nullable Ref<PyType> getReferenceType(@NotNull PsiElement referenceTarget, @NotNull TypeEvalContext context, @Nullable PsiElement anchor) {
|
||||
public @Nullable Ref<PyType> getReferenceType(@NotNull PsiElement referenceTarget,
|
||||
@NotNull TypeEvalContext context,
|
||||
@Nullable PsiElement anchor) {
|
||||
if (!(referenceTarget instanceof PyDecoratable pyDecoratable)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+4
-3
@@ -85,10 +85,10 @@ public class PyFunctionTypeAnnotationParser extends PyParser {
|
||||
assert atToken(PyTokenTypes.LPAR);
|
||||
final SyntaxTreeBuilder.Marker listMark = myBuilder.mark();
|
||||
myBuilder.advanceLexer();
|
||||
|
||||
|
||||
final ExpressionParsing exprParser = getExpressionParser();
|
||||
int paramCount = 0;
|
||||
while (!(atAnyOfTokens(PyTokenTypes.RPAR, PyTokenTypes.RARROW, PyTokenTypes.STATEMENT_BREAK) || myBuilder.eof()) ) {
|
||||
while (!(atAnyOfTokens(PyTokenTypes.RPAR, PyTokenTypes.RARROW, PyTokenTypes.STATEMENT_BREAK) || myBuilder.eof())) {
|
||||
if (paramCount > 0) {
|
||||
checkMatches(PyTokenTypes.COMMA, PyParsingBundle.message("PARSE.expected.comma"));
|
||||
}
|
||||
@@ -110,7 +110,8 @@ public class PyFunctionTypeAnnotationParser extends PyParser {
|
||||
}
|
||||
if (!parsed) {
|
||||
myBuilder.error(PyParsingBundle.message("PARSE.expected.expression"));
|
||||
recoverUntilMatches(PyParsingBundle.message("PARSE.expected.expression"), PyTokenTypes.COMMA, PyTokenTypes.RPAR, PyTokenTypes.RARROW, PyTokenTypes.STATEMENT_BREAK);
|
||||
recoverUntilMatches(PyParsingBundle.message("PARSE.expected.expression"), PyTokenTypes.COMMA, PyTokenTypes.RPAR,
|
||||
PyTokenTypes.RARROW, PyTokenTypes.STATEMENT_BREAK);
|
||||
}
|
||||
paramCount++;
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,8 +31,8 @@ public class PyFunctionTypeAnnotation extends PyElementImpl {
|
||||
|
||||
public @NotNull PyParameterTypeList getParameterTypeList() {
|
||||
return findNotNullChildByClass(PyParameterTypeList.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public @Nullable PyExpression getReturnType() {
|
||||
return findChildByClass(PyExpression.class);
|
||||
}
|
||||
|
||||
+5
-3
@@ -64,7 +64,9 @@ public final class AddImportHelper {
|
||||
}
|
||||
|
||||
public static @NotNull Comparator<String> getImportTextComparator(@NotNull PsiFile settingsAnchor) {
|
||||
return PythonCodeStyleService.getInstance().isOptimizeImportsCaseSensitiveOrder(settingsAnchor) ? String.CASE_INSENSITIVE_ORDER : Comparator.naturalOrder();
|
||||
return PythonCodeStyleService.getInstance().isOptimizeImportsCaseSensitiveOrder(settingsAnchor)
|
||||
? String.CASE_INSENSITIVE_ORDER
|
||||
: Comparator.naturalOrder();
|
||||
}
|
||||
|
||||
private static @NotNull List<String> getSortNames(@NotNull PyImportStatementBase importStatement) {
|
||||
@@ -161,7 +163,6 @@ public final class AddImportHelper {
|
||||
if (parentElement != null) {
|
||||
parentElement.addBefore(generator.createFromImportStatement(languageLevel, qualifier, name, asName), anchor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static @Nullable PsiElement getLocalInsertPosition(@NotNull PsiElement anchor) {
|
||||
@@ -368,7 +369,8 @@ public final class AddImportHelper {
|
||||
return getImportPriorityWithReason(importStatement, resolvedFileOrDir);
|
||||
}
|
||||
|
||||
static @NotNull ImportPriorityChoice getImportPriorityWithReason(@NotNull PsiElement importLocation, @NotNull PsiFileSystemItem toImport) {
|
||||
static @NotNull ImportPriorityChoice getImportPriorityWithReason(@NotNull PsiElement importLocation,
|
||||
@NotNull PsiFileSystemItem toImport) {
|
||||
final VirtualFile vFile = toImport.getVirtualFile();
|
||||
if (vFile == null) {
|
||||
return new ImportPriorityChoice(UNRESOLVED_SYMBOL_PRIORITY, toImport + " doesn't have an associated virtual file");
|
||||
|
||||
+3
-1
@@ -100,7 +100,9 @@ public class ImportCandidateHolder implements Comparable<ImportCandidateHolder>
|
||||
* @param source known ImportElement to import the name; its 'as' clause is used if present.
|
||||
* @return a properly qualified name.
|
||||
*/
|
||||
public static @NotNull String getQualifiedName(@NotNull String name, @Nullable QualifiedName importPath, @Nullable PyImportElement source) {
|
||||
public static @NotNull String getQualifiedName(@NotNull String name,
|
||||
@Nullable QualifiedName importPath,
|
||||
@Nullable PyImportElement source) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (source != null) {
|
||||
final PsiElement parent = source.getParent();
|
||||
|
||||
+3
-4
@@ -34,9 +34,9 @@ public class ImportFromExistingAction implements QuestionAction {
|
||||
private final boolean myImportLocally;
|
||||
|
||||
/**
|
||||
* @param target element to become qualified as imported.
|
||||
* @param sources clauses of import to be used.
|
||||
* @param name relevant name ot the target element (e.g. of identifier in an expression).
|
||||
* @param target element to become qualified as imported.
|
||||
* @param sources clauses of import to be used.
|
||||
* @param name relevant name ot the target element (e.g. of identifier in an expression).
|
||||
* @param insertBefore import statement should be inserted right before this element. However, if it aims at an insertion statement in
|
||||
* a group of inserts, a better insertion point belonging the group may be chosen, and it can be after the specified
|
||||
* node. If null, the position will be chosen automatically.
|
||||
@@ -201,5 +201,4 @@ public class ImportFromExistingAction implements QuestionAction {
|
||||
myOnDoneCallback.run();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import com.jetbrains.python.psi.resolve.QualifiedNameFinder
|
||||
/**
|
||||
* @author Aleksei Kniazev
|
||||
*/
|
||||
class PyRelativeImportData private constructor(val relativeLocation: String, val relativeLevel: Int) {
|
||||
class PyRelativeImportData private constructor(val relativeLocation: String, val relativeLevel: Int) {
|
||||
|
||||
val locationWithDots: String
|
||||
get() = ".".repeat(relativeLevel) + relativeLocation
|
||||
|
||||
+31
-15
@@ -51,7 +51,7 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
while (scanner.find(index)) {
|
||||
if (scanner.start() > 1) {
|
||||
// handle escaping sequences PY-977
|
||||
if ("{".equals(scanner.group(0)) && "\\N".equals(source.subSequence(scanner.start()-2, scanner.start()).toString())) {
|
||||
if ("{".equals(scanner.group(0)) && "\\N".equals(source.subSequence(scanner.start() - 2, scanner.start()).toString())) {
|
||||
skipClosingBrace = true;
|
||||
target.append(source.subSequence(index, scanner.end()));
|
||||
index = scanner.end();
|
||||
@@ -66,8 +66,12 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
}
|
||||
|
||||
target.append(source.subSequence(index, scanner.start()));
|
||||
if ("{".equals(scanner.group(0))) target.append("{{");
|
||||
else target.append("}}");
|
||||
if ("{".equals(scanner.group(0))) {
|
||||
target.append("{{");
|
||||
}
|
||||
else {
|
||||
target.append("}}");
|
||||
}
|
||||
index = scanner.end();
|
||||
}
|
||||
target.append(source.subSequence(index, source.length()));
|
||||
@@ -75,6 +79,7 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
|
||||
/**
|
||||
* Converts format expressions inside a string
|
||||
*
|
||||
* @return a pair of string builder with resulting string expression and a flag which is true if formats inside use mapping by name.
|
||||
*/
|
||||
private static Pair<StringBuilder, Boolean> convertFormat(PyStringLiteralExpression stringLiteralExpression, String prefix) {
|
||||
@@ -97,12 +102,12 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
sure("\"'".indexOf(quote) >= 0);
|
||||
if (text.length() - openPos >= 6) {
|
||||
// triple-quoted?
|
||||
if (text.charAt(openPos+1) == quote && text.charAt(openPos+2) == quote) {
|
||||
if (text.charAt(openPos + 1) == quote && text.charAt(openPos + 2) == quote) {
|
||||
openPos += 2;
|
||||
}
|
||||
}
|
||||
int index = openPos + 1; // from quote to first in-string char
|
||||
StringBuilder out = new StringBuilder(text.subSequence(0, openPos+1));
|
||||
StringBuilder out = new StringBuilder(text.subSequence(0, openPos + 1));
|
||||
if (!hasPrefix) out.insert(0, prefix);
|
||||
Matcher scanner = FORMAT_PATTERN.matcher(text);
|
||||
while (scanner.find(index)) {
|
||||
@@ -136,7 +141,9 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
if (f_width != null) {
|
||||
out.append(f_width);
|
||||
}
|
||||
if ("i".equals(fConversion) || "u".equals(fConversion)) out.append("d");
|
||||
if ("i".equals(fConversion) || "u".equals(fConversion)) {
|
||||
out.append("d");
|
||||
}
|
||||
else if (!"s".equals(fConversion) && !"r".equals(fConversion)) out.append(fConversion);
|
||||
|
||||
final int lastIndexOf = out.lastIndexOf(":");
|
||||
@@ -164,7 +171,7 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
int left = prev_range.getEndOffset() - full_start;
|
||||
int right = next_range.getStartOffset() - full_start;
|
||||
if (left < right) {
|
||||
constants.get(fragment_no-1).append(full_text.subSequence(left, right));
|
||||
constants.get(fragment_no - 1).append(full_text.subSequence(left, right));
|
||||
}
|
||||
fragment_no += 1;
|
||||
prev_range = next_range;
|
||||
@@ -173,7 +180,7 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
final int right = full_range.getEndOffset() - full_start;
|
||||
if (left < right) {
|
||||
// the barely possible case of last dangling "\"
|
||||
constants.get(constants.size()-1).append(full_text.subSequence(left, right));
|
||||
constants.get(constants.size() - 1).append(full_text.subSequence(left, right));
|
||||
}
|
||||
|
||||
// join everything
|
||||
@@ -219,12 +226,13 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
return false;
|
||||
}
|
||||
|
||||
PyBinaryExpression binaryExpression =
|
||||
PyBinaryExpression binaryExpression =
|
||||
PsiTreeUtil.getParentOfType(psiFile.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class, false);
|
||||
if (binaryExpression == null) {
|
||||
return false;
|
||||
}
|
||||
if (binaryExpression.getLeftExpression() instanceof PyStringLiteralExpression str && binaryExpression.getOperator() == PyTokenTypes.PERC) {
|
||||
if (binaryExpression.getLeftExpression() instanceof PyStringLiteralExpression str &&
|
||||
binaryExpression.getOperator() == PyTokenTypes.PERC) {
|
||||
if ((!str.getText().isEmpty() && Character.toUpperCase(str.getText().charAt(0)) == 'B')) {
|
||||
return false;
|
||||
}
|
||||
@@ -290,7 +298,9 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
else if (PyTypeUtil.isDict(rhsType)) {
|
||||
target.append("(**").append(paramText).append(")");
|
||||
}
|
||||
else target.append("(").append(paramText).append(")"); // tuple is ok as is
|
||||
else {
|
||||
target.append("(").append(paramText).append(")"); // tuple is ok as is
|
||||
}
|
||||
// Correctly handle multiline implicitly concatenated string literals (PY-9176)
|
||||
target.insert(0, '(').append(')');
|
||||
final PyExpression parenthesized = elementGenerator.createExpressionFromText(LanguageLevel.forElement(element), target.toString());
|
||||
@@ -313,13 +323,15 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
String separator = ""; // detect nontrivial whitespace around the "%"
|
||||
Pair<String, PsiElement> crop = collectWhitespace(leftExpression);
|
||||
String maybeSeparator = crop.getFirst();
|
||||
if (maybeSeparator != null && !maybeSeparator.isEmpty() && !" ".equals(maybeSeparator))
|
||||
if (maybeSeparator != null && !maybeSeparator.isEmpty() && !" ".equals(maybeSeparator)) {
|
||||
separator = maybeSeparator;
|
||||
}
|
||||
else { // after "%"
|
||||
crop = collectWhitespace(crop.getSecond());
|
||||
maybeSeparator = crop.getFirst();
|
||||
if (maybeSeparator != null && !maybeSeparator.isEmpty() && !" ".equals(maybeSeparator))
|
||||
if (maybeSeparator != null && !maybeSeparator.isEmpty() && !" ".equals(maybeSeparator)) {
|
||||
separator = maybeSeparator;
|
||||
}
|
||||
}
|
||||
return separator;
|
||||
}
|
||||
@@ -329,8 +341,12 @@ public final class ConvertFormatOperatorToMethodIntention extends PyBaseIntentio
|
||||
PsiElement seeker = start;
|
||||
while (seeker != null) {
|
||||
seeker = seeker.getNextSibling();
|
||||
if (seeker instanceof PsiWhiteSpace) sb.append(seeker.getText());
|
||||
else break;
|
||||
if (seeker instanceof PsiWhiteSpace) {
|
||||
sb.append(seeker.getText());
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Pair.create(sb.toString(), seeker);
|
||||
}
|
||||
|
||||
+5
-4
@@ -23,14 +23,15 @@ public final class DeclarationConflictChecker {
|
||||
/**
|
||||
* For each reference in the collection, finds a definition of name visible from the point of the reference. Returns a list of
|
||||
* such definitions.
|
||||
* @param name what to look for.
|
||||
*
|
||||
* @param name what to look for.
|
||||
* @param references references to check.
|
||||
* @param ignored if an element defining the name is also listed here, ignore it.
|
||||
* @param ignored if an element defining the name is also listed here, ignore it.
|
||||
* @return a list of pairs (referring element, element that defines name).
|
||||
*/
|
||||
public static @NotNull List<Pair<PsiElement, PsiElement>> findDefinitions(@NotNull String name,
|
||||
@NotNull Collection<? extends PsiReference> references,
|
||||
@NotNull Set<PsiElement> ignored) {
|
||||
@NotNull Collection<? extends PsiReference> references,
|
||||
@NotNull Set<PsiElement> ignored) {
|
||||
final List<Pair<PsiElement, PsiElement>> conflicts = new ArrayList<>();
|
||||
for (PsiReference ref : references) {
|
||||
final PsiElement refElement = ref.getElement();
|
||||
|
||||
+23
-9
@@ -93,7 +93,9 @@ public final class ImportFromToImportIntention extends PyBaseIntentionAction {
|
||||
if (remaining_module instanceof PyQualifiedExpression) {
|
||||
remaining_name = PyPsiUtils.toPath((PyQualifiedExpression)remaining_module);
|
||||
}
|
||||
else remaining_name = ""; // unqualified name: "...module"
|
||||
else {
|
||||
remaining_name = ""; // unqualified name: "...module"
|
||||
}
|
||||
separated_name = info.myModuleReference.getReferencedName();
|
||||
failure = false;
|
||||
if (separated_name == null) {
|
||||
@@ -101,13 +103,17 @@ public final class ImportFromToImportIntention extends PyBaseIntentionAction {
|
||||
failure = true;
|
||||
}
|
||||
}
|
||||
if (strict && failure) return null;
|
||||
else return new String[] {getDots(info.myRelativeLevel)+remaining_name, separated_name};
|
||||
if (strict && failure) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return new String[]{getDots(info.myRelativeLevel) + remaining_name, separated_name};
|
||||
}
|
||||
}
|
||||
|
||||
private static String getDots(int level) {
|
||||
String dots = "";
|
||||
for (int i=0; i<level; i+=1) dots += "."; // this generally runs 1-2 times, so it's cheaper than allocating a StringBuilder
|
||||
for (int i = 0; i < level; i += 1) dots += "."; // this generally runs 1-2 times, so it's cheaper than allocating a StringBuilder
|
||||
return dots;
|
||||
}
|
||||
|
||||
@@ -157,12 +163,15 @@ public final class ImportFromToImportIntention extends PyBaseIntentionAction {
|
||||
|
||||
/**
|
||||
* Adds myModuleName as a qualifier to target.
|
||||
*
|
||||
* @param target_node what to qualify
|
||||
*/
|
||||
private static void qualifyTarget(ASTNode target_node, Project project, String qualifier) {
|
||||
final PyElementGenerator generator = PyElementGenerator.getInstance(project);
|
||||
target_node.addChild(generator.createDot(), target_node.getFirstChildNode());
|
||||
target_node.addChild(sure(generator.createFromText(LanguageLevel.getDefault(), PyReferenceExpression.class, qualifier, new int[]{0,0}).getNode()), target_node.getFirstChildNode());
|
||||
target_node.addChild(
|
||||
sure(generator.createFromText(LanguageLevel.getDefault(), PyReferenceExpression.class, qualifier, new int[]{0, 0}).getNode()),
|
||||
target_node.getFirstChildNode());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,14 +179,17 @@ public final class ImportFromToImportIntention extends PyBaseIntentionAction {
|
||||
InfoHolder info = InfoHolder.collect(getElementFromEditor(editor, file));
|
||||
try {
|
||||
String qualifier; // we don't always qualify with module name
|
||||
sure(info.myModuleReference); sure(info.myModuleName);
|
||||
sure(info.myModuleReference);
|
||||
sure(info.myModuleName);
|
||||
String[] relative_names = null; // [0] is remaining import path, [1] is imported module name
|
||||
if (info.myRelativeLevel > 0) {
|
||||
relative_names = getRelativeNames(true, info);
|
||||
if (relative_names == null) throw new IncorrectOperationException("failed to get relative names");
|
||||
qualifier = relative_names[1];
|
||||
}
|
||||
else qualifier = info.myModuleName;
|
||||
else {
|
||||
qualifier = info.myModuleName;
|
||||
}
|
||||
// find all unqualified references that lead to one of our import elements
|
||||
final PyImportElement[] ielts = info.myFromImportStatement.getImportElements();
|
||||
final PyStarImportElement star_ielt = info.myFromImportStatement.getStarImportElement();
|
||||
@@ -211,7 +223,8 @@ public final class ImportFromToImportIntention extends PyBaseIntentionAction {
|
||||
sure(feeler instanceof PyQualifiedExpression); // if for some crazy reason module name refers to numbers, etc, no point to continue.
|
||||
top_qualifier = (PyQualifiedExpression)feeler;
|
||||
feeler = top_qualifier.getQualifier();
|
||||
} while (feeler != null);
|
||||
}
|
||||
while (feeler != null);
|
||||
String top_name = top_qualifier.getName();
|
||||
Collection<PsiReference> possible_targets = references.keySet();
|
||||
if (!star_references.isEmpty()) {
|
||||
@@ -262,7 +275,8 @@ public final class ImportFromToImportIntention extends PyBaseIntentionAction {
|
||||
new_import = sure(generator.createFromText(level, PyImportStatement.class, "import " + info.myModuleName));
|
||||
}
|
||||
else {
|
||||
new_import = sure(generator.createFromText(level, PyFromImportStatement.class, "from " + relative_names[0] + " import " + relative_names[1]));
|
||||
new_import =
|
||||
sure(generator.createFromText(level, PyFromImportStatement.class, "from " + relative_names[0] + " import " + relative_names[1]));
|
||||
}
|
||||
ASTNode parent = sure(info.myFromImportStatement.getParent().getNode());
|
||||
ASTNode old_node = sure(info.myFromImportStatement.getNode());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user