mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
highlight keyword argument after **kwarg as error (PY-9934)
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
@@ -138,7 +139,7 @@ public class PyArgumentListInspection extends PyInspection {
|
||||
holder.registerProblem(arg, PyBundle.message("INSP.duplicate.star.arg"));
|
||||
}
|
||||
if (flags.contains(CallArgumentsMapping.ArgFlag.IS_POS_PAST_KWD)) {
|
||||
holder.registerProblem(arg, PyBundle.message("INSP.cannot.appear.past.keyword.arg"));
|
||||
holder.registerProblem(arg, PyBundle.message("INSP.cannot.appear.past.keyword.arg"), ProblemHighlightType.ERROR);
|
||||
}
|
||||
if (flags.contains(CallArgumentsMapping.ArgFlag.IS_UNMAPPED)) {
|
||||
holder.registerProblem(arg, PyBundle.message("INSP.unexpected.arg"));
|
||||
|
||||
@@ -180,15 +180,9 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
|
||||
for (PyExpression arg : unmatched_subargs) {
|
||||
markArgument(arg, ArgFlag.IS_UNMAPPED);
|
||||
}
|
||||
// mark past-bound positional args
|
||||
i = positional_bound;
|
||||
while (i<arguments.length) {
|
||||
PyExpression arg = arguments[i];
|
||||
if (!(arg instanceof PyStarArgument) && !(arg instanceof PyKeywordArgument)) {
|
||||
markArgument(arg, ArgFlag.IS_POS_PAST_KWD);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
markPastBoundPositionalArguments(arguments, positional_bound);
|
||||
|
||||
boolean seen_named_args = false;
|
||||
// map named args to named params if possible
|
||||
Map<String, PyNamedParameter> parameter_by_name = new LinkedHashMap<String, PyNamedParameter>();
|
||||
@@ -352,6 +346,19 @@ public class CallArgumentsMappingImpl implements CallArgumentsMapping {
|
||||
}
|
||||
}
|
||||
|
||||
private void markPastBoundPositionalArguments(PyExpression[] arguments, int positionalBound) {
|
||||
boolean seenKwArg = false;
|
||||
for(int i=positionalBound; i<arguments.length; i++) {
|
||||
PyExpression arg = arguments[i];
|
||||
if (arg == myKwdArg) {
|
||||
seenKwArg = true;
|
||||
}
|
||||
if (!(arg instanceof PyStarArgument) && (seenKwArg || !(arg instanceof PyKeywordArgument))) {
|
||||
markArgument(arg, ArgFlag.IS_POS_PAST_KWD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPositionalArg(PyExpression arg) {
|
||||
return !(arg instanceof PyKeywordArgument) && !(arg instanceof PyStarArgument);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ f3(1, 2, <warning descr="Unexpected argument">3</warning>)
|
||||
f3(b=2, a=1)
|
||||
f3(b=1, <warning descr="Duplicate argument">b=2</warning>, a=1)
|
||||
f3(1, b=2)
|
||||
f3(a=1, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">2</warning><warning descr="Parameter 'b' unfilled">)</warning>
|
||||
f3(a=1, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">2</error><warning descr="Parameter 'b' unfilled">)</warning>
|
||||
|
||||
def f4(a, *b):
|
||||
pass
|
||||
@@ -52,4 +52,4 @@ f4(1, 2)
|
||||
f4(1, 2, 3)
|
||||
f4(1, *(2, 3))
|
||||
f4(*(1,2,3))
|
||||
f4(a=1, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">2</warning>, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">3</warning>)
|
||||
f4(a=1, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">2</error>, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">3</error>)
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
def foo(**kwargs): pass
|
||||
|
||||
two = 0
|
||||
kw = {}
|
||||
foo(**kw, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">two=1</error>)
|
||||
@@ -19,7 +19,7 @@ def f2(a, b, c=1, *d):
|
||||
f2(c=3, *(1,2))
|
||||
f2(1,2,3, *(1,2))
|
||||
f2(*(1,2), c=20)
|
||||
f2(*(1,2), <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">20</warning>) # fail: positional past *
|
||||
f2(*(1,2), <error descr="Cannot appear past keyword arguments or *arg or **kwarg">20</error>) # fail: positional past *
|
||||
|
||||
def f3(a=1, b=2, c=3, *d):
|
||||
return a,b,c,d
|
||||
|
||||
@@ -13,7 +13,7 @@ namedpast(1,2,3, foo='a') # pass
|
||||
namedpast(*args, foo='b') # pass
|
||||
namedpast(foo='c') # pass
|
||||
namedpast() # pass
|
||||
namedpast(foo='1', <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">2</warning>) # fail
|
||||
namedpast(foo='1', <error descr="Cannot appear past keyword arguments or *arg or **kwarg">2</error>) # fail
|
||||
|
||||
def a23(a, *b, c=1):
|
||||
pass
|
||||
@@ -21,7 +21,7 @@ def a23(a, *b, c=1):
|
||||
a23(1,2,3, c=10) # pass
|
||||
a23(1,2,3, c=10, <warning descr="Duplicate argument">a=1</warning>) # fail
|
||||
a23(c=10, a=1) # pass
|
||||
a23(c=10, <warning descr="Cannot appear past keyword arguments or *arg or **kwarg">1</warning><warning descr="Parameter 'a' unfilled">)</warning> # fail
|
||||
a23(c=10, <error descr="Cannot appear past keyword arguments or *arg or **kwarg">1</error><warning descr="Parameter 'a' unfilled">)</warning> # fail
|
||||
a23(<warning descr="Multiple values resolve to positional parameter 'a'">*args</warning>, a=1) # fail
|
||||
a23(*args, c=1) # pass
|
||||
|
||||
|
||||
@@ -168,4 +168,8 @@ public class PyArgumentListInspectionTest extends PyTestCase {
|
||||
public void testDictFromKeys() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testParameterWithDefaultAfterKeywordContainer() { // PY-9934
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user