mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fix mapping arguments to parameters for functions with positional-only parameters (PEP 570) (PY-35512)
GitOrigin-RevId: 7306430f4a9562855a958b91250ce65c29b3dba3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2ddb4c886c
commit
221ecaea49
@@ -8,6 +8,7 @@ import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.intellij.psi.ResolveResult;
|
||||
@@ -86,7 +87,9 @@ public class PyArgumentListInspection extends PyInspection {
|
||||
else { // possible unfilled params
|
||||
for (int i = firstParamOffset; i < params.size(); i++) {
|
||||
final PyCallableParameter parameter = params.get(i);
|
||||
if (parameter.getParameter() instanceof PySingleStarParameter) continue;
|
||||
if (parameter.getParameter() instanceof PySingleStarParameter || parameter.getParameter() instanceof PySlashParameter) {
|
||||
continue;
|
||||
}
|
||||
// param tuples, non-starred or non-default won't do
|
||||
if (!parameter.isKeywordContainer() && !parameter.isPositionalContainer() && !parameter.hasDefaultValue()) {
|
||||
final String parameterName = parameter.getName();
|
||||
|
||||
@@ -859,6 +859,7 @@ public class PyCallExpressionHelper {
|
||||
@NotNull
|
||||
private static ArgumentMappingResults analyzeArguments(@NotNull List<PyExpression> arguments,
|
||||
@NotNull List<PyCallableParameter> parameters) {
|
||||
boolean positionalOnlyMode = ContainerUtil.exists(parameters, p -> p.getParameter() instanceof PySlashParameter);
|
||||
boolean seenSingleStar = false;
|
||||
boolean mappedVariadicArgumentsToParameters = false;
|
||||
final Map<PyExpression, PyCallableParameter> mappedParameters = new LinkedHashMap<>();
|
||||
@@ -920,7 +921,17 @@ public class PyCallExpressionHelper {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (allPositionalArguments.isEmpty()) {
|
||||
if (positionalOnlyMode) {
|
||||
final PyExpression positionalArgument = next(allPositionalArguments);
|
||||
|
||||
if (positionalArgument != null) {
|
||||
mappedParameters.put(positionalArgument, parameter);
|
||||
}
|
||||
else if (!parameter.hasDefaultValue()) {
|
||||
unmappedParameters.add(parameter);
|
||||
}
|
||||
}
|
||||
else if (allPositionalArguments.isEmpty()) {
|
||||
final PyKeywordArgument keywordArgument = removeKeywordArgument(keywordArguments, parameterName);
|
||||
if (keywordArgument != null) {
|
||||
mappedParameters.put(keywordArgument, parameter);
|
||||
@@ -970,6 +981,9 @@ public class PyCallExpressionHelper {
|
||||
mappedVariadicArgumentsToParameters = true;
|
||||
}
|
||||
}
|
||||
else if (psi instanceof PySlashParameter) {
|
||||
positionalOnlyMode = false;
|
||||
}
|
||||
else if (psi instanceof PySingleStarParameter) {
|
||||
seenSingleStar = true;
|
||||
}
|
||||
@@ -1285,15 +1299,6 @@ public class PyCallExpressionHelper {
|
||||
return list.isEmpty() ? null : list.remove(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PyCallableParameter> dropImplicitParameters(@NotNull List<PyCallableParameter> parameters, int offset) {
|
||||
final ArrayList<PyCallableParameter> results = new ArrayList<>(parameters);
|
||||
for (int i = 0; i < offset && !results.isEmpty(); i++) {
|
||||
results.remove(0);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PyCallableParameter> filterExplicitParameters(@NotNull List<PyCallableParameter> parameters,
|
||||
@Nullable PyCallable callable,
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
def foo(a, /, b, *args, c, **kwargs):
|
||||
print(a, b, args, c, kwargs)
|
||||
|
||||
# valid
|
||||
# b as positional
|
||||
foo(1, 2, c=3)
|
||||
foo(1, 2, 3, c=3)
|
||||
foo(1, 2, 3, c=3, d=4)
|
||||
|
||||
# b as keyword
|
||||
foo(1, b=2, c=3)
|
||||
foo(1, c=3, b=2)
|
||||
|
||||
# invalid
|
||||
foo(<warning descr="Parameter 'a' unfilled"><warning descr="Parameter 'b' unfilled"><warning descr="Parameter 'c' unfilled">)</warning></warning></warning>
|
||||
foo(c=3<warning descr="Parameter 'a' unfilled"><warning descr="Parameter 'b' unfilled">)</warning></warning>
|
||||
foo(b=2, c=3<warning descr="Parameter 'a' unfilled">)</warning>
|
||||
foo(a=1, b=2, c=3<warning descr="Parameter 'a' unfilled">)</warning>
|
||||
|
||||
|
||||
def foo2(a, /, b=2, *args, c, **kwargs):
|
||||
print(a, b, args, c, kwargs)
|
||||
|
||||
# valid
|
||||
# b as positional
|
||||
foo2(1, 2, c=3)
|
||||
foo2(1, 2, 3, c=3)
|
||||
foo2(1, 2, 3, c=3, d=4)
|
||||
|
||||
# b as keyword
|
||||
foo2(1, b=2, c=3)
|
||||
foo2(1, c=3, b=2)
|
||||
|
||||
# no b
|
||||
foo2(1, c=3)
|
||||
|
||||
# invalid
|
||||
foo2(<warning descr="Parameter 'a' unfilled"><warning descr="Parameter 'c' unfilled">)</warning></warning>
|
||||
foo2(c=3<warning descr="Parameter 'a' unfilled">)</warning>
|
||||
foo2(b=2, c=3<warning descr="Parameter 'a' unfilled">)</warning>
|
||||
foo2(a=1, b=2, c=3<warning descr="Parameter 'a' unfilled">)</warning>
|
||||
|
||||
|
||||
def foo3(a=1, /, b=2, *args, c, **kwargs):
|
||||
print(a, b, args, c, kwargs)
|
||||
|
||||
# valid
|
||||
# b as positional
|
||||
foo3(1, 2, c=3)
|
||||
foo3(1, 2, 3, c=3)
|
||||
foo3(1, 2, 3, c=3, d=4)
|
||||
|
||||
# b as keyword
|
||||
foo3(1, b=2, c=3)
|
||||
foo3(1, c=3, b=2)
|
||||
|
||||
# no b
|
||||
foo3(1, c=3)
|
||||
|
||||
# no a, b as positional
|
||||
foo3(2, c=3)
|
||||
foo3(2, 3, c=3)
|
||||
foo3(2, 3, c=3, d=4)
|
||||
|
||||
# no a, b as keyword
|
||||
foo3(b=2, c=3)
|
||||
foo3(c=3, b=2)
|
||||
|
||||
# no a, no b
|
||||
foo3(c=3)
|
||||
foo3(a=1, b=2, c=3) # a goes to kwargs
|
||||
|
||||
# invalid
|
||||
foo3(<warning descr="Parameter 'c' unfilled">)</warning>
|
||||
|
||||
|
||||
def foo4(a=1, /, b=2, *args, c):
|
||||
print(a, b, args, c)
|
||||
|
||||
# invalid
|
||||
foo4(<warning descr="Unexpected argument">a=1</warning>, b=2, c=3)
|
||||
@@ -376,4 +376,9 @@ public class PyArgumentListInspectionTest extends PyInspectionTestCase {
|
||||
public void testAnotherMethodIsWrappedIntoStatic() {
|
||||
doMultiFileTest();
|
||||
}
|
||||
|
||||
// PY-35512
|
||||
public void testPositionalOnlyParameters() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON38, this::doTest);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user