mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[python] refactoring: Introduce PyAstNamedParameter.isPositionalOnly
GitOrigin-RevId: f072b2135128fdfb1d46dca68232968b20a6b078
This commit is contained in:
committed by
intellij-monorepo-bot
parent
47c7fff641
commit
ac5f5705e0
@@ -18,6 +18,7 @@ package com.jetbrains.python.ast;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.jetbrains.python.PyNamesKt;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.PythonDialectsTokenSetProvider;
|
||||
import com.jetbrains.python.ast.impl.ParamHelperCore;
|
||||
@@ -136,6 +137,48 @@ public interface PyAstNamedParameter extends PyAstParameter, PsiNamedElement, Ps
|
||||
return varargSeen;
|
||||
}
|
||||
|
||||
default boolean isPositionalOnly() {
|
||||
if (isSelf() ||
|
||||
isKeywordContainer() ||
|
||||
isPositionalContainer() ||
|
||||
this instanceof PyAstSingleStarParameter ||
|
||||
this instanceof PyAstSlashParameter) {
|
||||
return false;
|
||||
}
|
||||
final PyAstParameterList parameters = getStubOrPsiParentOfType(PyAstParameterList.class);
|
||||
if (parameters == null) {
|
||||
return false;
|
||||
}
|
||||
boolean thisSeen = false;
|
||||
boolean allBeforeThisPrivate = true;
|
||||
for (PyAstParameter param : parameters.getParameters()) {
|
||||
if (param.isSelf()) {
|
||||
continue;
|
||||
}
|
||||
if (param instanceof PyAstSingleStarParameter ||
|
||||
(param instanceof PyAstNamedParameter np && (np.isPositionalContainer() || np.isKeywordContainer()))) {
|
||||
// None of the positional-only parameter kinds can follow these
|
||||
if (!thisSeen) {
|
||||
return false;
|
||||
}
|
||||
// No need to continue, as `/` can't follow them either
|
||||
break;
|
||||
}
|
||||
// New-style positional-only syntax, decide purely by the position
|
||||
if (param instanceof PyAstSlashParameter) {
|
||||
return thisSeen;
|
||||
}
|
||||
if (param == this) {
|
||||
thisSeen = true;
|
||||
}
|
||||
else if (!thisSeen) {
|
||||
allBeforeThisPrivate &= param.getName() != null && PyNamesKt.isPrivate(param.getName());
|
||||
}
|
||||
}
|
||||
// Legacy-style positional only
|
||||
return thisSeen && allBeforeThisPrivate && getName() != null && PyNamesKt.isPrivate(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isSelf() {
|
||||
if (isPositionalContainer() || isKeywordContainer()) {
|
||||
|
||||
@@ -152,4 +152,57 @@ public class PyMiscellaneousPsiOperationsTest extends PyTestCase {
|
||||
final PyQualifiedExpression expr = (PyQualifiedExpression)generator.createExpressionFromText(LanguageLevel.PYTHON27, expression);
|
||||
assertEquals(expectedQualifiedName, expr.asQualifiedName());
|
||||
}
|
||||
|
||||
public void testNamedParameterIsPositionalOnly() {
|
||||
doTestParameterIsPositionalOnly(List.of(false, true, true, false, false), """
|
||||
class C:
|
||||
def func(__self, __a, __b, c, __d):
|
||||
pass
|
||||
""");
|
||||
doTestParameterIsPositionalOnly(List.of(true, true), """
|
||||
class C:
|
||||
@staticmethod
|
||||
def func(__self, __a):
|
||||
pass
|
||||
""");
|
||||
doTestParameterIsPositionalOnly(List.of(false, true), """
|
||||
class C:
|
||||
@classmethod
|
||||
def func(__self, __a):
|
||||
pass
|
||||
""");
|
||||
doTestParameterIsPositionalOnly(List.of(true, true), """
|
||||
def func(__self, __a):
|
||||
pass
|
||||
""");
|
||||
doTestParameterIsPositionalOnly(List.of(false, true, false, false), """
|
||||
class C:
|
||||
def func(self, __a, *__args, __b):
|
||||
pass
|
||||
""");
|
||||
doTestParameterIsPositionalOnly(List.of(false, true, false, false), """
|
||||
class C:
|
||||
def func(self, __a, *, __b):
|
||||
pass
|
||||
""");
|
||||
doTestParameterIsPositionalOnly(List.of(false, true, false), """
|
||||
class C:
|
||||
def func(self, __a, **__kwargs):
|
||||
pass
|
||||
""");
|
||||
doTestParameterIsPositionalOnly(List.of(false, true, false, false), """
|
||||
class C:
|
||||
def func(self, a, /, __b):
|
||||
pass
|
||||
""");
|
||||
}
|
||||
|
||||
private void doTestParameterIsPositionalOnly(List<Boolean> expected, String testData) {
|
||||
myFixture.configureByText("a.py", testData);
|
||||
PyFunction func = myFixture.findElementByText("func", PyFunction.class);
|
||||
assertNotNull(func);
|
||||
List<Boolean> actual = ContainerUtil.map(func.getParameterList().getParameters(),
|
||||
p -> p instanceof PyNamedParameter np && np.isPositionalOnly());
|
||||
assertOrderedEquals(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user