Skip to content

Commit 1cd04c9

Browse files
committed
Python: Fix bug in handling of **kwargs in class bases
This caused a dataset check error on the `python/cpython` database, as we had a `DictUnpacking` node whose parent was not a `dict_item_list`, but rather an `expr_list`. Investigating a bit further revealed that this was because in a construction like ```python class C[T](base, foo=bar, **kwargs): ... ``` we were mistakenly adding `**kwargs` to the same list as `base` (which is just a list of expressions), rather than the same list as `foo=bar` (which is a list of dictionary items) The ultimate cause of this was the use of `! name` in `python.tsg` to distinguish between bases and keyword arguments (only the latter of which have the `name` field). Because `dictionary_splat` doesn't have a `name` field either, these were mistakenly put in the wrong list, leading to the error. Also, because our previous test of `class` statements did not include a `**kwargs` construction, we were not checking that the new parser behaved correctly in this case. For the most part this was not a problem, but on files that use syntax not supported by the old parser (like type parameters on classes), this became an issue. This is also why we did not see this error previously. To fix this, we added `! value` (which is a field present on `dictionary_splat` nodes) as a secondary filter, and added a third stanza to handle `dictionary_splat` nodes.
1 parent f3abe54 commit 1cd04c9

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

python/extractor/tsg-python/python.tsg

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,16 +1277,18 @@
12771277
attr (@class.inner_scope -> @stmt.node) body = (named-child-index @stmt)
12781278
}
12791279

1280-
; Class.bases - using `(_ !name)` as a proxy for all non-keyword arguments.
1280+
; Class.bases - using `(_ !value !name)` as a proxy for all non-keyword arguments.
1281+
; In particular, `keyword_argument` nodes have a `name` field, and `dictionary_splat`
1282+
; nodes have a `value` field.
12811283
(class_definition
1282-
superclasses: (argument_list element: (_ !name) @arg)
1284+
superclasses: (argument_list element: (_ !value !name) @arg)
12831285
) @class
12841286
{
12851287
edge @class.class_expr -> @arg.node
12861288
attr (@class.class_expr -> @arg.node) bases = (named-child-index @arg)
12871289
}
12881290

1289-
; Class.keywords
1291+
; Class.keywords of the form `foo=bar`
12901292
(class_definition
12911293
superclasses: (argument_list element: (keyword_argument) @arg)
12921294
) @class
@@ -1295,6 +1297,15 @@
12951297
attr (@class.class_expr -> @arg.node) keywords = (named-child-index @arg)
12961298
}
12971299

1300+
; Class.keywords of the form `**kwargs`
1301+
(class_definition
1302+
superclasses: (argument_list element: (dictionary_splat) @arg)
1303+
) @class
1304+
{
1305+
edge @class.class_expr -> @arg.node
1306+
attr (@class.class_expr -> @arg.node) keywords = (named-child-index @arg)
1307+
}
1308+
12981309
;;;;;; End of Class
12991310

13001311
;;;;;; Assign statements

0 commit comments

Comments
 (0)