Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/libcst/matchers/_matcher_base.py: 41%
574 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:43 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:43 +0000
1# Copyright (c) Meta Platforms, Inc. and affiliates.
2#
3# This source code is licensed under the MIT license found in the
4# LICENSE file in the root directory of this source tree.
6import collections.abc
7import inspect
8import re
9from abc import ABCMeta
10from dataclasses import dataclass, fields
11from enum import auto, Enum
12from typing import (
13 Callable,
14 cast,
15 Dict,
16 Generic,
17 Iterator,
18 List,
19 Mapping,
20 NoReturn,
21 Optional,
22 Pattern,
23 Sequence,
24 Tuple,
25 Type,
26 TypeVar,
27 Union,
28)
30import libcst
31import libcst.metadata as meta
32from libcst import FlattenSentinel, MaybeSentinel, RemovalSentinel
33from libcst._metadata_dependent import LazyValue
36class DoNotCareSentinel(Enum):
37 """
38 A sentinel that is used in matcher classes to indicate that a caller
39 does not care what this value is. We recommend that you do not use this
40 directly, and instead use the :func:`DoNotCare` helper. You do not
41 need to use this for concrete matcher attributes since :func:`DoNotCare`
42 is already the default.
43 """
45 DEFAULT = auto()
47 def __repr__(self) -> str:
48 return "DoNotCare()"
51_MatcherT = TypeVar("_MatcherT", covariant=True)
52_MatchIfTrueT = TypeVar("_MatchIfTrueT", covariant=True)
53_BaseMatcherNodeSelfT = TypeVar("_BaseMatcherNodeSelfT", bound="BaseMatcherNode")
54_OtherNodeT = TypeVar("_OtherNodeT")
55_MetadataValueT = TypeVar("_MetadataValueT")
56_MatcherTypeT = TypeVar("_MatcherTypeT", bound=Type["BaseMatcherNode"])
57_OtherNodeMatcherTypeT = TypeVar(
58 "_OtherNodeMatcherTypeT", bound=Type["BaseMatcherNode"]
59)
62_METADATA_MISSING_SENTINEL = object()
65class AbstractBaseMatcherNodeMeta(ABCMeta):
66 """
67 Metaclass that all matcher nodes uses. Allows chaining 2 node type
68 together with an bitwise-or operator to produce an :class:`TypeOf`
69 matcher.
70 """
72 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
73 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
74 def __or__(self, node: Type["BaseMatcherNode"]) -> "TypeOf[Type[BaseMatcherNode]]":
75 return TypeOf(self, node)
78class BaseMatcherNode:
79 """
80 Base class that all concrete matchers subclass from. :class:`OneOf` and
81 :class:`AllOf` also subclass from this in order to allow them to be used in
82 any place that a concrete matcher is allowed. This means that, for example,
83 you can call :func:`matches` with a concrete matcher, or a :class:`OneOf` with
84 several concrete matchers as options.
85 """
87 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
88 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
89 def __or__(
90 self: _BaseMatcherNodeSelfT, other: _OtherNodeT
91 ) -> "OneOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]]":
92 # Without a cast, pyre thinks that the below OneOf is type OneOf[object]
93 # even though it has the types passed into it.
94 return cast(
95 OneOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]], OneOf(self, other)
96 )
98 def __and__(
99 self: _BaseMatcherNodeSelfT, other: _OtherNodeT
100 ) -> "AllOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]]":
101 # Without a cast, pyre thinks that the below AllOf is type AllOf[object]
102 # even though it has the types passed into it.
103 return cast(
104 AllOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]], AllOf(self, other)
105 )
107 def __invert__(self: _BaseMatcherNodeSelfT) -> "_BaseMatcherNodeSelfT":
108 return cast(_BaseMatcherNodeSelfT, _InverseOf(self))
111def DoNotCare() -> DoNotCareSentinel:
112 """
113 Used when you want to match exactly one node, but you do not care what node it is.
114 Useful inside sequences such as a :class:`libcst.matchers.Call`'s args attribte.
115 You do not need to use this for concrete matcher attributes since :func:`DoNotCare`
116 is already the default.
118 For example, the following matcher would match against any function calls with
119 three arguments, regardless of the arguments themselves and regardless of the
120 function name that we were calling::
122 m.Call(args=[m.DoNotCare(), m.DoNotCare(), m.DoNotCare()])
123 """
124 return DoNotCareSentinel.DEFAULT
127class TypeOf(Generic[_MatcherTypeT], BaseMatcherNode):
128 """
129 Matcher that matches any one of the given types. Useful when you want to work
130 with trees where a common property might belong to more than a single type.
132 For example, if you want either a binary operation or a boolean operation
133 where the left side has a name ``foo``::
135 m.TypeOf(m.BinaryOperation, m.BooleanOperation)(left = m.Name("foo"))
137 Or you could use the shorthand, like::
139 (m.BinaryOperation | m.BooleanOperation)(left = m.Name("foo"))
141 Also :class:`TypeOf` matchers can be used with initalizing in the default
142 state of other node matchers (without passing any extra patterns)::
144 m.Name | m.SimpleString
146 The will be equal to::
148 m.OneOf(m.Name(), m.SimpleString())
149 """
151 def __init__(self, *options: Union[_MatcherTypeT, "TypeOf[_MatcherTypeT]"]) -> None:
152 actual_options: List[_MatcherTypeT] = []
153 for option in options:
154 if isinstance(option, TypeOf):
155 if option.initalized:
156 raise Exception(
157 "Cannot chain an uninitalized TypeOf with an initalized one"
158 )
159 actual_options.extend(option._raw_options)
160 else:
161 actual_options.append(option)
163 self._initalized = False
164 self._call_items: Tuple[Tuple[object, ...], Dict[str, object]] = ((), {})
165 self._raw_options: Tuple[_MatcherTypeT, ...] = tuple(actual_options)
167 @property
168 def initalized(self) -> bool:
169 return self._initalized
171 @property
172 def options(self) -> Iterator[BaseMatcherNode]:
173 for option in self._raw_options:
174 args, kwargs = self._call_items
175 matcher_pattern = option(*args, **kwargs)
176 yield matcher_pattern
178 def __call__(self, *args: object, **kwargs: object) -> BaseMatcherNode:
179 self._initalized = True
180 self._call_items = (args, kwargs)
181 return self
183 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
184 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
185 def __or__(
186 self, other: _OtherNodeMatcherTypeT
187 ) -> "TypeOf[Union[_MatcherTypeT, _OtherNodeMatcherTypeT]]":
188 return TypeOf[Union[_MatcherTypeT, _OtherNodeMatcherTypeT]](self, other)
190 # pyre-fixme[14]: `__and__` overrides method defined in `BaseMatcherNode`
191 # inconsistently.
192 def __and__(self, other: _OtherNodeMatcherTypeT) -> NoReturn:
193 left, right = type(self).__name__, other.__name__
194 raise TypeError(
195 f"TypeError: unsupported operand type(s) for &: {left!r} and {right!r}"
196 )
198 def __invert__(self) -> "AllOf[BaseMatcherNode]":
199 return AllOf(*map(DoesNotMatch, self.options))
201 def __repr__(self) -> str:
202 types = ", ".join(repr(option) for option in self._raw_options)
203 return f"TypeOf({types}, initalized = {self.initalized})"
206class OneOf(Generic[_MatcherT], BaseMatcherNode):
207 """
208 Matcher that matches any one of its options. Useful when you want to match
209 against one of several options for a single node. You can also construct a
210 :class:`OneOf` matcher by using Python's bitwise or operator with concrete
211 matcher classes.
213 For example, you could match against ``True``/``False`` like::
215 m.OneOf(m.Name("True"), m.Name("False"))
217 Or you could use the shorthand, like::
219 m.Name("True") | m.Name("False")
221 """
223 def __init__(self, *options: Union[_MatcherT, "OneOf[_MatcherT]"]) -> None:
224 actual_options: List[_MatcherT] = []
225 for option in options:
226 if isinstance(option, AllOf):
227 raise Exception("Cannot use AllOf and OneOf in combination!")
228 elif isinstance(option, (OneOf, TypeOf)):
229 actual_options.extend(option.options)
230 else:
231 actual_options.append(option)
232 self._options: Sequence[_MatcherT] = tuple(actual_options)
234 @property
235 def options(self) -> Sequence[_MatcherT]:
236 """
237 The normalized list of options that we can choose from to satisfy a
238 :class:`OneOf` matcher. If any of these matchers are true, the
239 :class:`OneOf` matcher will also be considered a match.
240 """
241 return self._options
243 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
244 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
245 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[_MatcherT, _OtherNodeT]]":
246 # Without a cast, pyre thinks that the below OneOf is type OneOf[object]
247 # even though it has the types passed into it.
248 return cast(OneOf[Union[_MatcherT, _OtherNodeT]], OneOf(self, other))
250 def __and__(self, other: _OtherNodeT) -> NoReturn:
251 raise Exception("Cannot use AllOf and OneOf in combination!")
253 def __invert__(self) -> "AllOf[_MatcherT]":
254 # Invert using De Morgan's Law so we don't have to complicate types.
255 return cast(AllOf[_MatcherT], AllOf(*[DoesNotMatch(m) for m in self._options]))
257 def __repr__(self) -> str:
258 return f"OneOf({', '.join([repr(o) for o in self._options])})"
261class AllOf(Generic[_MatcherT], BaseMatcherNode):
262 """
263 Matcher that matches all of its options. Useful when you want to match
264 against a concrete matcher and a :class:`MatchIfTrue` at the same time. Also
265 useful when you want to match against a concrete matcher and a
266 :func:`DoesNotMatch` at the same time. You can also construct a
267 :class:`AllOf` matcher by using Python's bitwise and operator with concrete
268 matcher classes.
270 For example, you could match against ``True`` in a roundabout way like::
272 m.AllOf(m.Name(), m.Name("True"))
274 Or you could use the shorthand, like::
276 m.Name() & m.Name("True")
278 Similar to :class:`OneOf`, this can be used in place of any concrete matcher.
280 Real-world cases where :class:`AllOf` is useful are hard to come by but they
281 are still provided for the limited edge cases in which they make sense. In
282 the example above, we are redundantly matching against any LibCST
283 :class:`~libcst.Name` node as well as LibCST :class:`~libcst.Name` nodes that
284 have the ``value`` of ``True``. We could drop the first option entirely and
285 get the same result. Often, if you are using a :class:`AllOf`,
286 you can refactor your code to be simpler.
288 For example, the following matches any function call to ``foo``, and
289 any function call which takes zero arguments::
291 m.AllOf(m.Call(func=m.Name("foo")), m.Call(args=()))
293 This could be refactored into the following equivalent concrete matcher::
295 m.Call(func=m.Name("foo"), args=())
297 """
299 def __init__(self, *options: Union[_MatcherT, "AllOf[_MatcherT]"]) -> None:
300 actual_options: List[_MatcherT] = []
301 for option in options:
302 if isinstance(option, OneOf):
303 raise Exception("Cannot use AllOf and OneOf in combination!")
304 elif isinstance(option, TypeOf):
305 raise Exception("Cannot use AllOf and TypeOf in combination!")
306 elif isinstance(option, AllOf):
307 actual_options.extend(option.options)
308 else:
309 actual_options.append(option)
310 self._options: Sequence[_MatcherT] = tuple(actual_options)
312 @property
313 def options(self) -> Sequence[_MatcherT]:
314 """
315 The normalized list of options that we can choose from to satisfy a
316 :class:`AllOf` matcher. If all of these matchers are true, the
317 :class:`AllOf` matcher will also be considered a match.
318 """
319 return self._options
321 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
322 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
323 def __or__(self, other: _OtherNodeT) -> NoReturn:
324 raise Exception("Cannot use AllOf and OneOf in combination!")
326 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[_MatcherT, _OtherNodeT]]":
327 # Without a cast, pyre thinks that the below AllOf is type AllOf[object]
328 # even though it has the types passed into it.
329 return cast(AllOf[Union[_MatcherT, _OtherNodeT]], AllOf(self, other))
331 def __invert__(self) -> "OneOf[_MatcherT]":
332 # Invert using De Morgan's Law so we don't have to complicate types.
333 return cast(OneOf[_MatcherT], OneOf(*[DoesNotMatch(m) for m in self._options]))
335 def __repr__(self) -> str:
336 return f"AllOf({', '.join([repr(o) for o in self._options])})"
339class _InverseOf(Generic[_MatcherT]):
340 """
341 Matcher that inverts the match result of its child. You can also construct a
342 :class:`_InverseOf` matcher by using Python's bitwise invert operator with concrete
343 matcher classes or any special matcher.
345 Note that you should refrain from constructing a :class:`_InverseOf` directly, and
346 should instead use the :func:`DoesNotMatch` helper function.
348 For example, the following matches against any identifier that isn't
349 ``True``/``False``::
351 m.DoesNotMatch(m.OneOf(m.Name("True"), m.Name("False")))
353 Or you could use the shorthand, like:
355 ~(m.Name("True") | m.Name("False"))
357 """
359 def __init__(self, matcher: _MatcherT) -> None:
360 self._matcher: _MatcherT = matcher
362 @property
363 def matcher(self) -> _MatcherT:
364 """
365 The matcher that we will evaluate and invert. If this matcher is true, then
366 :class:`_InverseOf` will be considered not a match, and vice-versa.
367 """
368 return self._matcher
370 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
371 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
372 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[_MatcherT, _OtherNodeT]]":
373 # Without a cast, pyre thinks that the below OneOf is type OneOf[object]
374 # even though it has the types passed into it.
375 return cast(OneOf[Union[_MatcherT, _OtherNodeT]], OneOf(self, other))
377 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[_MatcherT, _OtherNodeT]]":
378 # Without a cast, pyre thinks that the below AllOf is type AllOf[object]
379 # even though it has the types passed into it.
380 return cast(AllOf[Union[_MatcherT, _OtherNodeT]], AllOf(self, other))
382 def __getattr__(self, key: str) -> object:
383 # We lie about types to make _InverseOf appear transparent. So, its conceivable
384 # that somebody might try to dereference an attribute on the _MatcherT wrapped
385 # node and become surprised that it doesn't work.
386 return getattr(self._matcher, key)
388 def __invert__(self) -> _MatcherT:
389 return self._matcher
391 def __repr__(self) -> str:
392 return f"DoesNotMatch({repr(self._matcher)})"
395class _ExtractMatchingNode(Generic[_MatcherT]):
396 """
397 Transparent pass-through matcher that captures the node which matches its children,
398 making it available to the caller of :func:`extract` or :func:`extractall`.
400 Note that you should refrain from constructing a :class:`_ExtractMatchingNode`
401 directly, and should instead use the :func:`SaveMatchedNode` helper function.
403 For example, the following will match against any binary operation whose left
404 and right operands are not integers, saving those expressions for later inspection.
405 If used inside :func:`extract` or :func:`extractall`, the resulting dictionary will
406 contain the keys ``left_operand`` and ``right_operand``.
408 m.BinaryOperation(
409 left=m.SaveMatchedNode(
410 m.DoesNotMatch(m.Integer()),
411 "left_operand",
412 ),
413 right=m.SaveMatchedNode(
414 m.DoesNotMatch(m.Integer()),
415 "right_operand",
416 ),
417 )
418 """
420 def __init__(self, matcher: _MatcherT, name: str) -> None:
421 self._matcher: _MatcherT = matcher
422 self._name: str = name
424 @property
425 def matcher(self) -> _MatcherT:
426 """
427 The matcher that we will evaluate and capture matching LibCST nodes for.
428 If this matcher is true, then :class:`_ExtractMatchingNode` will be considered
429 a match and will save the node which matched.
430 """
431 return self._matcher
433 @property
434 def name(self) -> str:
435 """
436 The name we will call our captured LibCST node inside the resulting dictionary
437 returned by :func:`extract` or :func:`extractall`.
438 """
439 return self._name
441 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
442 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
443 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[_MatcherT, _OtherNodeT]]":
444 # Without a cast, pyre thinks that the below OneOf is type OneOf[object]
445 # even though it has the types passed into it.
446 return cast(OneOf[Union[_MatcherT, _OtherNodeT]], OneOf(self, other))
448 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[_MatcherT, _OtherNodeT]]":
449 # This doesn't make sense. If we have multiple SaveMatchedNode captures
450 # that are captured with an and, either all of them will be assigned the
451 # same node, or none of them. It makes more sense to move the SaveMatchedNode
452 # up to wrap the AllOf.
453 raise Exception(
454 (
455 "Cannot use AllOf with SavedMatchedNode children! Instead, you should "
456 + "use SaveMatchedNode(AllOf(options...))."
457 )
458 )
460 def __getattr__(self, key: str) -> object:
461 # We lie about types to make _ExtractMatchingNode appear transparent. So,
462 # its conceivable that somebody might try to dereference an attribute on
463 # the _MatcherT wrapped node and become surprised that it doesn't work.
464 return getattr(self._matcher, key)
466 def __invert__(self) -> "_MatcherT":
467 # This doesn't make sense. We don't want to capture a node only if it
468 # doesn't match, since this will never capture anything.
469 raise Exception(
470 (
471 "Cannot invert a SaveMatchedNode. Instead you should wrap SaveMatchedNode "
472 + "around your inversion itself"
473 )
474 )
476 def __repr__(self) -> str:
477 return (
478 f"SaveMatchedNode(matcher={repr(self._matcher)}, name={repr(self._name)})"
479 )
482class MatchIfTrue(Generic[_MatchIfTrueT]):
483 """
484 Matcher that matches if its child callable returns ``True``. The child callable
485 should take one argument which is the attribute on the LibCST node we are
486 trying to match against. This is useful if you want to do complex logic to
487 determine if an attribute should match or not. One example of this is the
488 :func:`MatchRegex` matcher build on top of :class:`MatchIfTrue` which takes a
489 regular expression and matches any string attribute where a regex match is found.
491 For example, to match on any identifier spelled with the letter ``e``::
493 m.Name(value=m.MatchIfTrue(lambda value: "e" in value))
495 This can be used in place of any concrete matcher as long as it is not the
496 root matcher. Calling :func:`matches` directly on a :class:`MatchIfTrue` is
497 redundant since you can just call the child callable directly with the node
498 you are passing to :func:`matches`.
499 """
501 _func: Callable[[_MatchIfTrueT], bool]
503 def __init__(self, func: Callable[[_MatchIfTrueT], bool]) -> None:
504 self._func = func
506 @property
507 def func(self) -> Callable[[_MatchIfTrueT], bool]:
508 """
509 The function that we will call with a LibCST node in order to determine
510 if we match. If the function returns ``True`` then we consider ourselves
511 to be a match.
512 """
513 return self._func
515 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
516 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
517 def __or__(
518 self, other: _OtherNodeT
519 ) -> "OneOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]]":
520 # Without a cast, pyre thinks that the below OneOf is type OneOf[object]
521 # even though it has the types passed into it.
522 return cast(
523 OneOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]], OneOf(self, other)
524 )
526 def __and__(
527 self, other: _OtherNodeT
528 ) -> "AllOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]]":
529 # Without a cast, pyre thinks that the below AllOf is type AllOf[object]
530 # even though it has the types passed into it.
531 return cast(
532 AllOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]], AllOf(self, other)
533 )
535 def __invert__(self) -> "MatchIfTrue[_MatchIfTrueT]":
536 # Construct a wrapped version of MatchIfTrue for typing simplicity.
537 # Without the cast, pyre doesn't seem to think the lambda is valid.
538 return MatchIfTrue(lambda val: not self._func(val))
540 def __repr__(self) -> str:
541 return f"MatchIfTrue({repr(self._func)})"
544def MatchRegex(regex: Union[str, Pattern[str]]) -> MatchIfTrue[str]:
545 """
546 Used as a convenience wrapper to :class:`MatchIfTrue` which allows for
547 matching a string attribute against a regex. ``regex`` can be any regular
548 expression string or a compiled ``Pattern``. This uses Python's re module
549 under the hood and is compatible with syntax documented on
550 `docs.python.org <https://docs.python.org/3/library/re.html>`_.
552 For example, to match against any identifier that is at least one character
553 long and only contains alphabetical characters::
555 m.Name(value=m.MatchRegex(r'[A-Za-z]+'))
557 This can be used in place of any string literal when constructing a concrete
558 matcher.
559 """
561 def _match_func(value: object) -> bool:
562 if isinstance(value, str):
563 # pyre-ignore Pyre doesn't think a 'Pattern' can be passed to fullmatch.
564 return bool(re.fullmatch(regex, value))
565 else:
566 return False
568 return MatchIfTrue(_match_func)
571class _BaseMetadataMatcher:
572 """
573 Class that's only around for typing purposes.
574 """
576 pass
579class MatchMetadata(_BaseMetadataMatcher):
580 """
581 Matcher that looks up the metadata on the current node using the provided
582 metadata provider and compares the value on the node against the value provided
583 to :class:`MatchMetadata`.
584 If the metadata provider is unresolved, a :class:`LookupError` exeption will be
585 raised and ask you to provide a :class:`~libcst.metadata.MetadataWrapper`.
586 If the metadata value does not exist for a particular node, :class:`MatchMetadata`
587 will be considered not a match.
589 For example, to match against any function call which has one parameter which
590 is used in a load expression context::
592 m.Call(
593 args=[
594 m.Arg(
595 m.MatchMetadata(
596 meta.ExpressionContextProvider,
597 meta.ExpressionContext.LOAD,
598 )
599 )
600 ]
601 )
603 To match against any :class:`~libcst.Name` node for the identifier ``foo``
604 which is the target of an assignment::
606 m.Name(
607 value="foo",
608 metadata=m.MatchMetadata(
609 meta.ExpressionContextProvider,
610 meta.ExpressionContext.STORE,
611 )
612 )
614 This can be used in place of any concrete matcher as long as it is not the
615 root matcher. Calling :func:`matches` directly on a :class:`MatchMetadata` is
616 redundant since you can just check the metadata on the root node that you
617 are passing to :func:`matches`.
618 """
620 def __init__(
621 self,
622 key: Type[meta.BaseMetadataProvider[_MetadataValueT]],
623 value: _MetadataValueT,
624 ) -> None:
625 self._key: Type[meta.BaseMetadataProvider[_MetadataValueT]] = key
626 self._value: _MetadataValueT = value
628 @property
629 def key(self) -> meta.ProviderT:
630 """
631 The metadata provider that we will use to fetch values when identifying whether
632 a node matches this matcher. We compare the value returned from the metadata
633 provider to the value provided in ``value`` when determining a match.
634 """
635 return self._key
637 @property
638 def value(self) -> object:
639 """
640 The value that we will compare against the return from the metadata provider
641 for each node when determining a match.
642 """
643 return self._value
645 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
646 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
647 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[MatchMetadata, _OtherNodeT]]":
648 # Without the cast, pyre doesn't know this is valid
649 return cast(OneOf[Union[MatchMetadata, _OtherNodeT]], OneOf(self, other))
651 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[MatchMetadata, _OtherNodeT]]":
652 # Without the cast, pyre doesn't know this is valid
653 return cast(AllOf[Union[MatchMetadata, _OtherNodeT]], AllOf(self, other))
655 def __invert__(self) -> "MatchMetadata":
656 # We intentionally lie here, for the same reason given in the documentation
657 # for DoesNotMatch.
658 return cast(MatchMetadata, _InverseOf(self))
660 def __repr__(self) -> str:
661 return f"MatchMetadata(key={repr(self._key)}, value={repr(self._value)})"
664class MatchMetadataIfTrue(_BaseMetadataMatcher):
665 """
666 Matcher that looks up the metadata on the current node using the provided
667 metadata provider and passes it to a callable which can inspect the metadata
668 further, returning ``True`` if the matcher should be considered a match.
669 If the metadata provider is unresolved, a :class:`LookupError` exeption will be
670 raised and ask you to provide a :class:`~libcst.metadata.MetadataWrapper`.
671 If the metadata value does not exist for a particular node,
672 :class:`MatchMetadataIfTrue` will be considered not a match.
674 For example, to match against any arg whose qualified name might be
675 ``typing.Dict``::
677 m.Call(
678 args=[
679 m.Arg(
680 m.MatchMetadataIfTrue(
681 meta.QualifiedNameProvider,
682 lambda qualnames: any(n.name == "typing.Dict" for n in qualnames)
683 )
684 )
685 ]
686 )
688 To match against any :class:`~libcst.Name` node for the identifier ``foo``
689 as long as that identifier is found at the beginning of an unindented line::
691 m.Name(
692 value="foo",
693 metadata=m.MatchMetadataIfTrue(
694 meta.PositionProvider,
695 lambda position: position.start.column == 0,
696 )
697 )
699 This can be used in place of any concrete matcher as long as it is not the
700 root matcher. Calling :func:`matches` directly on a :class:`MatchMetadataIfTrue`
701 is redundant since you can just check the metadata on the root node that you
702 are passing to :func:`matches`.
703 """
705 def __init__(
706 self,
707 key: Type[meta.BaseMetadataProvider[_MetadataValueT]],
708 func: Callable[[_MetadataValueT], bool],
709 ) -> None:
710 self._key: Type[meta.BaseMetadataProvider[_MetadataValueT]] = key
711 self._func: Callable[[_MetadataValueT], bool] = func
713 @property
714 def key(self) -> meta.ProviderT:
715 """
716 The metadata provider that we will use to fetch values when identifying whether
717 a node matches this matcher. We pass the value returned from the metadata
718 provider to the callable given to us in ``func``.
719 """
720 return self._key
722 @property
723 def func(self) -> Callable[[object], bool]:
724 """
725 The function that we will call with a value retrieved from the metadata provider
726 provided in ``key``. If the function returns ``True`` then we consider ourselves
727 to be a match.
728 """
729 return self._func
731 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
732 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
733 def __or__(
734 self, other: _OtherNodeT
735 ) -> "OneOf[Union[MatchMetadataIfTrue, _OtherNodeT]]":
736 # Without the cast, pyre doesn't know this is valid
737 return cast(OneOf[Union[MatchMetadataIfTrue, _OtherNodeT]], OneOf(self, other))
739 def __and__(
740 self, other: _OtherNodeT
741 ) -> "AllOf[Union[MatchMetadataIfTrue, _OtherNodeT]]":
742 # Without the cast, pyre doesn't know this is valid
743 return cast(AllOf[Union[MatchMetadataIfTrue, _OtherNodeT]], AllOf(self, other))
745 def __invert__(self) -> "MatchMetadataIfTrue":
746 # Construct a wrapped version of MatchMetadataIfTrue for typing simplicity.
747 return MatchMetadataIfTrue(self._key, lambda val: not self._func(val))
749 def __repr__(self) -> str:
750 return f"MatchMetadataIfTrue(key={repr(self._key)}, func={repr(self._func)})"
753class _BaseWildcardNode:
754 """
755 A typing-only class for internal helpers in this module to be able to
756 specify that they take a wildcard node type.
757 """
759 pass
762class AtLeastN(Generic[_MatcherT], _BaseWildcardNode):
763 """
764 Matcher that matches ``n`` or more LibCST nodes in a row in a sequence.
765 :class:`AtLeastN` defaults to matching against the :func:`DoNotCare` matcher,
766 so if you do not specify a matcher as a child, :class:`AtLeastN`
767 will match only by count. If you do specify a matcher as a child,
768 :class:`AtLeastN` will instead make sure that each LibCST node matches the
769 matcher supplied.
771 For example, this will match all function calls with at least 3 arguments::
773 m.Call(args=[m.AtLeastN(n=3)])
775 This will match all function calls with 3 or more integer arguments::
777 m.Call(args=[m.AtLeastN(n=3, matcher=m.Arg(m.Integer()))])
779 You can combine sequence matchers with concrete matchers and special matchers
780 and it will behave as you expect. For example, this will match all function
781 calls that have 2 or more integer arguments in a row, followed by any arbitrary
782 argument::
784 m.Call(args=[m.AtLeastN(n=2, matcher=m.Arg(m.Integer())), m.DoNotCare()])
786 And finally, this will match all function calls that have at least 5
787 arguments, the final one being an integer::
789 m.Call(args=[m.AtLeastN(n=4), m.Arg(m.Integer())])
790 """
792 def __init__(
793 self,
794 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT,
795 *,
796 n: int,
797 ) -> None:
798 if n < 0:
799 raise Exception(f"{self.__class__.__name__} n attribute must be positive")
800 self._n: int = n
801 self._matcher: Union[_MatcherT, DoNotCareSentinel] = matcher
803 @property
804 def n(self) -> int:
805 """
806 The number of nodes in a row that must match :attr:`AtLeastN.matcher` for
807 this matcher to be considered a match. If there are less than ``n`` matches,
808 this matcher will not be considered a match. If there are equal to or more
809 than ``n`` matches, this matcher will be considered a match.
810 """
811 return self._n
813 @property
814 def matcher(self) -> Union[_MatcherT, DoNotCareSentinel]:
815 """
816 The matcher which each node in a sequence needs to match.
817 """
818 return self._matcher
820 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
821 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
822 def __or__(self, other: object) -> NoReturn:
823 raise Exception("AtLeastN cannot be used in a OneOf matcher")
825 def __and__(self, other: object) -> NoReturn:
826 raise Exception("AtLeastN cannot be used in an AllOf matcher")
828 def __invert__(self) -> NoReturn:
829 raise Exception("Cannot invert an AtLeastN matcher!")
831 def __repr__(self) -> str:
832 if self._n == 0:
833 return f"ZeroOrMore({repr(self._matcher)})"
834 else:
835 return f"AtLeastN({repr(self._matcher)}, n={self._n})"
838def ZeroOrMore(
839 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT
840) -> AtLeastN[Union[_MatcherT, DoNotCareSentinel]]:
841 """
842 Used as a convenience wrapper to :class:`AtLeastN` when ``n`` is equal to ``0``.
843 Use this when you want to match against any number of nodes in a sequence.
845 For example, this will match any function call with zero or more arguments, as
846 long as all of the arguments are integers::
848 m.Call(args=[m.ZeroOrMore(m.Arg(m.Integer()))])
850 This will match any function call where the first argument is an integer and
851 it doesn't matter what the rest of the arguments are::
853 m.Call(args=[m.Arg(m.Integer()), m.ZeroOrMore()])
855 You will often want to use :class:`ZeroOrMore` on both sides of a concrete
856 matcher in order to match against sequences that contain a particular node
857 in an arbitrary location. For example, the following will match any function
858 call that takes in at least one string argument anywhere::
860 m.Call(args=[m.ZeroOrMore(), m.Arg(m.SimpleString()), m.ZeroOrMore()])
861 """
862 return cast(AtLeastN[Union[_MatcherT, DoNotCareSentinel]], AtLeastN(matcher, n=0))
865class AtMostN(Generic[_MatcherT], _BaseWildcardNode):
866 """
867 Matcher that matches ``n`` or fewer LibCST nodes in a row in a sequence.
868 :class:`AtMostN` defaults to matching against the :func:`DoNotCare` matcher,
869 so if you do not specify a matcher as a child, :class:`AtMostN` will
870 match only by count. If you do specify a matcher as a child,
871 :class:`AtMostN` will instead make sure that each LibCST node matches the
872 matcher supplied.
874 For example, this will match all function calls with 3 or fewer arguments::
876 m.Call(args=[m.AtMostN(n=3)])
878 This will match all function calls with 0, 1 or 2 string arguments::
880 m.Call(args=[m.AtMostN(n=2, matcher=m.Arg(m.SimpleString()))])
882 You can combine sequence matchers with concrete matchers and special matchers
883 and it will behave as you expect. For example, this will match all function
884 calls that have 0, 1 or 2 string arguments in a row, followed by an arbitrary
885 argument::
887 m.Call(args=[m.AtMostN(n=2, matcher=m.Arg(m.SimpleString())), m.DoNotCare()])
889 And finally, this will match all function calls that have at least 2
890 arguments, the final one being a string::
892 m.Call(args=[m.AtMostN(n=2), m.Arg(m.SimpleString())])
893 """
895 def __init__(
896 self,
897 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT,
898 *,
899 n: int,
900 ) -> None:
901 if n < 0:
902 raise Exception(f"{self.__class__.__name__} n attribute must be positive")
903 self._n: int = n
904 self._matcher: Union[_MatcherT, DoNotCareSentinel] = matcher
906 @property
907 def n(self) -> int:
908 """
909 The number of nodes in a row that must match :attr:`AtLeastN.matcher` for
910 this matcher to be considered a match. If there are less than or equal to
911 ``n`` matches, then this matcher will be considered a match. Any more than
912 ``n`` matches in a row and this matcher will stop matching and be considered
913 not a match.
914 """
915 return self._n
917 @property
918 def matcher(self) -> Union[_MatcherT, DoNotCareSentinel]:
919 """
920 The matcher which each node in a sequence needs to match.
921 """
922 return self._matcher
924 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently.
925 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently.
926 def __or__(self, other: object) -> NoReturn:
927 raise Exception("AtMostN cannot be used in a OneOf matcher")
929 def __and__(self, other: object) -> NoReturn:
930 raise Exception("AtMostN cannot be used in an AllOf matcher")
932 def __invert__(self) -> NoReturn:
933 raise Exception("Cannot invert an AtMostN matcher!")
935 def __repr__(self) -> str:
936 if self._n == 1:
937 return f"ZeroOrOne({repr(self._matcher)})"
938 else:
939 return f"AtMostN({repr(self._matcher)}, n={self._n})"
942def ZeroOrOne(
943 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT
944) -> AtMostN[Union[_MatcherT, DoNotCareSentinel]]:
945 """
946 Used as a convenience wrapper to :class:`AtMostN` when ``n`` is equal to ``1``.
947 This is effectively a maybe clause.
949 For example, this will match any function call with zero or one integer
950 argument::
952 m.Call(args=[m.ZeroOrOne(m.Arg(m.Integer()))])
954 This will match any function call that has two or three arguments, and
955 the first and last arguments are strings::
957 m.Call(args=[m.Arg(m.SimpleString()), m.ZeroOrOne(), m.Arg(m.SimpleString())])
959 """
960 return cast(AtMostN[Union[_MatcherT, DoNotCareSentinel]], AtMostN(matcher, n=1))
963def DoesNotMatch(obj: _OtherNodeT) -> _OtherNodeT:
964 """
965 Matcher helper that inverts the match result of its child. You can also invert a
966 matcher by using Python's bitwise invert operator on concrete matchers or any
967 special matcher.
969 For example, the following matches against any identifier that isn't
970 ``True``/``False``::
972 m.DoesNotMatch(m.OneOf(m.Name("True"), m.Name("False")))
974 Or you could use the shorthand, like::
976 ~(m.Name("True") | m.Name("False"))
978 This can be used in place of any concrete matcher as long as it is not the
979 root matcher. Calling :func:`matches` directly on a :func:`DoesNotMatch` is
980 redundant since you can invert the return of :func:`matches` using a bitwise not.
981 """
983 # This type is a complete, dirty lie, but there's no way to recursively apply
984 # a parameter to each type inside a Union that may be in a _OtherNodeT.
985 # However, given the way _InverseOf works (it will unwrap itself if
986 # inverted again), and the way we apply De Morgan's law for OneOf and AllOf,
987 # this lie ends up getting us correct typing. Anywhere a node is valid, using
988 # DoesNotMatch(node) is also valid.
989 #
990 # ~MatchIfTrue is still MatchIfTrue
991 # ~MatchMetadataIfTrue is still MatchMetadataIfTrue
992 # ~OneOf[x] is AllOf[~x]
993 # ~AllOf[x] is OneOf[~x]
994 # ~~x is x
995 #
996 # So, under all circumstances, since OneOf/AllOf are both allowed in every
997 # instance, and given that inverting MatchIfTrue is still MatchIfTrue,
998 # and inverting an inverted value returns us the original, its clear that
999 # there are no operations we can possibly do that bring us outside of the
1000 # types specified in the concrete matchers as long as we lie that DoesNotMatch
1001 # returns the value passed in.
1002 if isinstance(
1003 obj,
1004 (
1005 BaseMatcherNode,
1006 MatchIfTrue,
1007 _BaseMetadataMatcher,
1008 _InverseOf,
1009 _ExtractMatchingNode,
1010 ),
1011 ):
1012 # We can use the overridden __invert__ in this case. Pyre doesn't think
1013 # we can though, and casting doesn't fix the issue.
1014 inverse = ~obj
1015 else:
1016 # We must wrap in a _InverseOf.
1017 inverse = _InverseOf(obj)
1018 return cast(_OtherNodeT, inverse)
1021def SaveMatchedNode(matcher: _OtherNodeT, name: str) -> _OtherNodeT:
1022 """
1023 Matcher helper that captures the matched node that matched against a matcher
1024 class, making it available in the dictionary returned by :func:`extract` or
1025 :func:`extractall`.
1027 For example, the following will match against any binary operation whose left
1028 and right operands are not integers, saving those expressions for later inspection.
1029 If used inside :func:`extract` or :func:`extractall`, the resulting dictionary
1030 will contain the keys ``left_operand`` and ``right_operand``::
1032 m.BinaryOperation(
1033 left=m.SaveMatchedNode(
1034 m.DoesNotMatch(m.Integer()),
1035 "left_operand",
1036 ),
1037 right=m.SaveMatchedNode(
1038 m.DoesNotMatch(m.Integer()),
1039 "right_operand",
1040 ),
1041 )
1043 This can be used in place of any concrete matcher as long as it is not the
1044 root matcher. Calling :func:`extract` directly on a :func:`SaveMatchedNode` is
1045 redundant since you already have the reference to the node itself.
1046 """
1047 return cast(_OtherNodeT, _ExtractMatchingNode(matcher, name))
1050def _matches_zero_nodes(
1051 matcher: Union[
1052 BaseMatcherNode,
1053 _BaseWildcardNode,
1054 MatchIfTrue[libcst.CSTNode],
1055 _BaseMetadataMatcher,
1056 DoNotCareSentinel,
1057 ]
1058) -> bool:
1059 if isinstance(matcher, AtLeastN) and matcher.n == 0:
1060 return True
1061 if isinstance(matcher, AtMostN):
1062 return True
1063 if isinstance(matcher, _ExtractMatchingNode):
1064 return _matches_zero_nodes(matcher.matcher)
1065 return False
1068@dataclass(frozen=True)
1069class _SequenceMatchesResult:
1070 sequence_capture: Optional[
1071 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]
1072 ]
1073 matched_nodes: Optional[
1074 Union[libcst.CSTNode, MaybeSentinel, Sequence[libcst.CSTNode]]
1075 ]
1078def _sequence_matches( # noqa: C901
1079 nodes: Sequence[Union[MaybeSentinel, libcst.CSTNode]],
1080 matchers: Sequence[
1081 Union[
1082 BaseMatcherNode,
1083 _BaseWildcardNode,
1084 MatchIfTrue[libcst.CSTNode],
1085 _BaseMetadataMatcher,
1086 DoNotCareSentinel,
1087 ]
1088 ],
1089 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object],
1090) -> _SequenceMatchesResult:
1091 if not nodes and not matchers:
1092 # Base case, empty lists are always matches
1093 return _SequenceMatchesResult({}, None)
1094 if not nodes and matchers:
1095 # Base case, we have one or more matcher that wasn't matched
1096 if all(_matches_zero_nodes(m) for m in matchers):
1097 return _SequenceMatchesResult(
1098 # pyre-ignore[16]: `MatchIfTrue` has no attribute `name`.
1099 {m.name: () for m in matchers if isinstance(m, _ExtractMatchingNode)},
1100 (),
1101 )
1102 else:
1103 return _SequenceMatchesResult(None, None)
1104 if nodes and not matchers:
1105 # Base case, we have nodes left that don't match any matcher
1106 return _SequenceMatchesResult(None, None)
1108 # Recursive case, nodes and matchers LHS matches
1109 node = nodes[0]
1110 matcher = matchers[0]
1111 if isinstance(matcher, DoNotCareSentinel):
1112 # We don't care about the value for this node.
1113 return _SequenceMatchesResult(
1114 _sequence_matches(
1115 nodes[1:], matchers[1:], metadata_lookup
1116 ).sequence_capture,
1117 node,
1118 )
1119 elif isinstance(matcher, _BaseWildcardNode):
1120 if isinstance(matcher, AtMostN):
1121 if matcher.n > 0:
1122 # First, assume that this does match a node (greedy).
1123 # Consume one node since it matched this matcher.
1124 attribute_capture = _attribute_matches(
1125 nodes[0], matcher.matcher, metadata_lookup
1126 )
1127 if attribute_capture is not None:
1128 result = _sequence_matches(
1129 nodes[1:],
1130 [AtMostN(matcher.matcher, n=matcher.n - 1), *matchers[1:]],
1131 metadata_lookup,
1132 )
1133 if result.sequence_capture is not None:
1134 matched = result.matched_nodes
1135 assert isinstance(matched, Sequence)
1136 return _SequenceMatchesResult(
1137 {**attribute_capture, **result.sequence_capture},
1138 # pyre-fixme[6]: Expected `Union[None, Sequence[libcst._n...
1139 (node, *matched),
1140 )
1141 # Finally, assume that this does not match the current node.
1142 # Consume the matcher but not the node.
1143 return _SequenceMatchesResult(
1144 _sequence_matches(
1145 nodes, matchers[1:], metadata_lookup
1146 ).sequence_capture,
1147 (),
1148 )
1149 elif isinstance(matcher, AtLeastN):
1150 if matcher.n > 0:
1151 # Only match if we can consume one of the matches, since we still
1152 # need to match N nodes.
1153 attribute_capture = _attribute_matches(
1154 nodes[0], matcher.matcher, metadata_lookup
1155 )
1156 if attribute_capture is not None:
1157 result = _sequence_matches(
1158 nodes[1:],
1159 [AtLeastN(matcher.matcher, n=matcher.n - 1), *matchers[1:]],
1160 metadata_lookup,
1161 )
1162 if result.sequence_capture is not None:
1163 matched = result.matched_nodes
1164 assert isinstance(matched, Sequence)
1165 return _SequenceMatchesResult(
1166 {**attribute_capture, **result.sequence_capture},
1167 # pyre-fixme[6]: Expected `Union[None, Sequence[libcst._n...
1168 (node, *matched),
1169 )
1170 return _SequenceMatchesResult(None, None)
1171 else:
1172 # First, assume that this does match a node (greedy).
1173 # Consume one node since it matched this matcher.
1174 attribute_capture = _attribute_matches(
1175 nodes[0], matcher.matcher, metadata_lookup
1176 )
1177 if attribute_capture is not None:
1178 result = _sequence_matches(nodes[1:], matchers, metadata_lookup)
1179 if result.sequence_capture is not None:
1180 matched = result.matched_nodes
1181 assert isinstance(matched, Sequence)
1182 return _SequenceMatchesResult(
1183 {**attribute_capture, **result.sequence_capture},
1184 # pyre-fixme[6]: Expected `Union[None, Sequence[libcst._n...
1185 (node, *matched),
1186 )
1187 # Now, assume that this does not match the current node.
1188 # Consume the matcher but not the node.
1189 return _SequenceMatchesResult(
1190 _sequence_matches(
1191 nodes, matchers[1:], metadata_lookup
1192 ).sequence_capture,
1193 (),
1194 )
1195 else:
1196 # There are no other types of wildcard consumers, but we're making
1197 # pyre happy with that fact.
1198 raise Exception(f"Logic error unrecognized wildcard {type(matcher)}!")
1199 elif isinstance(matcher, _ExtractMatchingNode):
1200 # See if the raw matcher matches. If it does, capture the sequence we matched and store it.
1201 result = _sequence_matches(
1202 nodes, [matcher.matcher, *matchers[1:]], metadata_lookup
1203 )
1204 if result.sequence_capture is not None:
1205 return _SequenceMatchesResult(
1206 {
1207 # Our own match capture comes first, since we wnat to allow the same
1208 # name later in the sequence to override us.
1209 matcher.name: result.matched_nodes,
1210 **result.sequence_capture,
1211 },
1212 result.matched_nodes,
1213 )
1214 return _SequenceMatchesResult(None, None)
1216 match_capture = _matches(node, matcher, metadata_lookup)
1217 if match_capture is not None:
1218 # These values match directly
1219 result = _sequence_matches(nodes[1:], matchers[1:], metadata_lookup)
1220 if result.sequence_capture is not None:
1221 return _SequenceMatchesResult(
1222 {**match_capture, **result.sequence_capture}, node
1223 )
1225 # Failed recursive case, no match
1226 return _SequenceMatchesResult(None, None)
1229_AttributeValueT = Optional[Union[MaybeSentinel, libcst.CSTNode, str, bool]]
1230_AttributeMatcherT = Optional[Union[BaseMatcherNode, DoNotCareSentinel, str, bool]]
1233def _attribute_matches( # noqa: C901
1234 node: Union[_AttributeValueT, Sequence[_AttributeValueT]],
1235 matcher: Union[_AttributeMatcherT, Sequence[_AttributeMatcherT]],
1236 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object],
1237) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]:
1238 if isinstance(matcher, DoNotCareSentinel):
1239 # We don't care what this is, so don't penalize a non-match.
1240 return {}
1241 if isinstance(matcher, _InverseOf):
1242 # Return the opposite evaluation
1243 return (
1244 {}
1245 if _attribute_matches(node, matcher.matcher, metadata_lookup) is None
1246 else None
1247 )
1248 if isinstance(matcher, _ExtractMatchingNode):
1249 attribute_capture = _attribute_matches(node, matcher.matcher, metadata_lookup)
1250 if attribute_capture is not None:
1251 return {
1252 # Our own match capture comes last, since its higher in the tree
1253 # so we want to override any child match captures by the same name.
1254 **attribute_capture,
1255 matcher.name: node,
1256 }
1257 return None
1259 if isinstance(matcher, MatchIfTrue):
1260 # We should only return if the matcher function is true.
1261 return {} if matcher.func(node) else None
1263 if matcher is None:
1264 # Should exactly be None
1265 return {} if node is None else None
1267 if isinstance(matcher, str):
1268 # Should exactly match matcher text
1269 return {} if node == matcher else None
1271 if isinstance(matcher, bool):
1272 # Should exactly match matcher bool
1273 return {} if node is matcher else None
1275 if isinstance(node, collections.abc.Sequence):
1276 # Given we've generated the types for matchers based on LibCST, we know that
1277 # this is true unless the node is badly constructed and types were ignored.
1278 node = cast(Sequence[Union[MaybeSentinel, libcst.CSTNode]], node)
1280 if isinstance(matcher, OneOf):
1281 # We should compare against each of the sequences in the OneOf
1282 for m in matcher.options:
1283 if isinstance(m, collections.abc.Sequence):
1284 # Should match the sequence of requested nodes
1285 result = _sequence_matches(node, m, metadata_lookup)
1286 if result.sequence_capture is not None:
1287 return result.sequence_capture
1288 elif isinstance(m, MatchIfTrue):
1289 # TODO: return captures
1290 return {} if m.func(node) else None
1291 elif isinstance(matcher, AllOf):
1292 # We should compare against each of the sequences in the AllOf
1293 all_captures = {}
1294 for m in matcher.options:
1295 if isinstance(m, collections.abc.Sequence):
1296 # Should match the sequence of requested nodes
1297 result = _sequence_matches(node, m, metadata_lookup)
1298 if result.sequence_capture is None:
1299 return None
1300 all_captures = {**all_captures, **result.sequence_capture}
1301 else:
1302 # The value in the AllOf wasn't a sequence, it can't match.
1303 return None
1304 # We passed the checks above for each node, so we passed.
1305 return all_captures
1306 elif isinstance(matcher, collections.abc.Sequence):
1307 # We should assume that this matcher is a sequence to compare. Given
1308 # the way we generate match classes, this should be true unless the
1309 # match is badly constructed and types were ignored.
1310 return _sequence_matches(
1311 node,
1312 cast(
1313 Sequence[
1314 Union[
1315 BaseMatcherNode,
1316 _BaseWildcardNode,
1317 MatchIfTrue[libcst.CSTNode],
1318 DoNotCareSentinel,
1319 ]
1320 ],
1321 matcher,
1322 ),
1323 metadata_lookup,
1324 ).sequence_capture
1326 # We exhausted our possibilities, there's no match
1327 return None
1329 # Base case, should match node via matcher. We know the type of node is
1330 # correct here because we generate matchers directly off of LibCST nodes,
1331 # so the only way it is wrong is if the node was badly constructed and
1332 # types were ignored.
1333 return _matches(
1334 cast(Union[MaybeSentinel, libcst.CSTNode], node),
1335 # pyre-fixme[24]: Generic type `MatchIfTrue` expects 1 type parameter.
1336 cast(Union[BaseMatcherNode, MatchIfTrue, _BaseMetadataMatcher], matcher),
1337 metadata_lookup,
1338 )
1341def _metadata_matches( # noqa: C901
1342 node: libcst.CSTNode,
1343 metadata: Union[
1344 _BaseMetadataMatcher,
1345 AllOf[_BaseMetadataMatcher],
1346 OneOf[_BaseMetadataMatcher],
1347 _InverseOf[_BaseMetadataMatcher],
1348 _ExtractMatchingNode[_BaseMetadataMatcher],
1349 ],
1350 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object],
1351) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]:
1352 if isinstance(metadata, OneOf):
1353 for metadata in metadata.options:
1354 metadata_capture = _metadata_matches(node, metadata, metadata_lookup)
1355 if metadata_capture is not None:
1356 return metadata_capture
1357 return None
1358 elif isinstance(metadata, AllOf):
1359 all_captures = {}
1360 for metadata in metadata.options:
1361 metadata_capture = _metadata_matches(node, metadata, metadata_lookup)
1362 if metadata_capture is None:
1363 return None
1364 all_captures = {**all_captures, **metadata_capture}
1365 # We passed the above checks, so we pass the matcher.
1366 return all_captures
1367 elif isinstance(metadata, _InverseOf):
1368 return (
1369 {}
1370 if _metadata_matches(node, metadata.matcher, metadata_lookup) is None
1371 else None
1372 )
1373 elif isinstance(metadata, _ExtractMatchingNode):
1374 metadata_capture = _metadata_matches(node, metadata.matcher, metadata_lookup)
1375 if metadata_capture is not None:
1376 return {
1377 # Our own match capture comes last, since its higher in the tree
1378 # so we want to override any child match captures by the same name.
1379 **metadata_capture,
1380 metadata.name: node,
1381 }
1382 return None
1383 elif isinstance(metadata, MatchMetadataIfTrue):
1384 actual_value = metadata_lookup(metadata.key, node)
1385 if actual_value is _METADATA_MISSING_SENTINEL:
1386 return None
1387 return {} if metadata.func(actual_value) else None
1388 elif isinstance(metadata, MatchMetadata):
1389 actual_value = metadata_lookup(metadata.key, node)
1390 if actual_value is _METADATA_MISSING_SENTINEL:
1391 return None
1392 return {} if actual_value == metadata.value else None
1393 else:
1394 raise Exception("Logic error!")
1397def _node_matches( # noqa: C901
1398 node: libcst.CSTNode,
1399 matcher: Union[
1400 BaseMatcherNode,
1401 MatchIfTrue[libcst.CSTNode],
1402 _BaseMetadataMatcher,
1403 _InverseOf[
1404 Union[
1405 BaseMatcherNode,
1406 MatchIfTrue[libcst.CSTNode],
1407 _BaseMetadataMatcher,
1408 ]
1409 ],
1410 _ExtractMatchingNode[
1411 Union[
1412 BaseMatcherNode,
1413 MatchIfTrue[libcst.CSTNode],
1414 _BaseMetadataMatcher,
1415 ]
1416 ],
1417 ],
1418 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object],
1419) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]:
1420 # If this is a _InverseOf, then invert the result.
1421 if isinstance(matcher, _InverseOf):
1422 return (
1423 {}
1424 if _node_matches(node, matcher.matcher, metadata_lookup) is None
1425 else None
1426 )
1428 # If this is an _ExtractMatchingNode, grab the resulting call and pass the check
1429 # forward.
1430 if isinstance(matcher, _ExtractMatchingNode):
1431 node_capture = _node_matches(node, matcher.matcher, metadata_lookup)
1432 if node_capture is not None:
1433 return {
1434 # We come last here since we're further up the tree, so we want to
1435 # override any identically named child match nodes.
1436 **node_capture,
1437 matcher.name: node,
1438 }
1439 return None
1441 # Now, check if this is a lambda matcher.
1442 if isinstance(matcher, MatchIfTrue):
1443 return {} if matcher.func(node) else None
1445 if isinstance(matcher, (MatchMetadata, MatchMetadataIfTrue)):
1446 return _metadata_matches(node, matcher, metadata_lookup)
1448 # Now, check that the node and matcher classes are the same.
1449 if node.__class__.__name__ != matcher.__class__.__name__:
1450 return None
1452 # Now, check that the children match for each attribute.
1453 all_captures = {}
1454 for field in fields(matcher):
1455 if field.name == "_metadata":
1456 # We don't care about this field, its a dataclasses implementation detail.
1457 continue
1458 elif field.name == "metadata":
1459 # Special field we respect for matching metadata on a particular node.
1460 desired = getattr(matcher, field.name)
1461 if isinstance(desired, DoNotCareSentinel):
1462 # We don't care about this
1463 continue
1464 metadata_capture = _metadata_matches(node, desired, metadata_lookup)
1465 if metadata_capture is None:
1466 return None
1467 all_captures = {**all_captures, **metadata_capture}
1468 else:
1469 desired = getattr(matcher, field.name)
1470 actual = getattr(node, field.name)
1471 attribute_capture = _attribute_matches(actual, desired, metadata_lookup)
1472 if attribute_capture is None:
1473 return None
1474 all_captures = {**all_captures, **attribute_capture}
1476 # We didn't find a non-match in the above loop, so it matches!
1477 return all_captures
1480def _matches(
1481 node: Union[MaybeSentinel, libcst.CSTNode],
1482 matcher: Union[
1483 BaseMatcherNode,
1484 MatchIfTrue[libcst.CSTNode],
1485 _BaseMetadataMatcher,
1486 _InverseOf[
1487 Union[
1488 BaseMatcherNode,
1489 MatchIfTrue[libcst.CSTNode],
1490 _BaseMetadataMatcher,
1491 ]
1492 ],
1493 _ExtractMatchingNode[
1494 Union[
1495 BaseMatcherNode,
1496 MatchIfTrue[libcst.CSTNode],
1497 _BaseMetadataMatcher,
1498 ]
1499 ],
1500 ],
1501 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object],
1502) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]:
1503 if isinstance(node, MaybeSentinel):
1504 # We can't possibly match on a maybe sentinel, so it only matches if
1505 # the matcher we have is a _InverseOf.
1506 return {} if isinstance(matcher, _InverseOf) else None
1508 # Now, evaluate the matcher node itself.
1509 if isinstance(matcher, (OneOf, TypeOf)):
1510 for matcher in matcher.options:
1511 node_capture = _node_matches(node, matcher, metadata_lookup)
1512 if node_capture is not None:
1513 return node_capture
1514 return None
1515 elif isinstance(matcher, AllOf):
1516 all_captures = {}
1517 for matcher in matcher.options:
1518 node_capture = _node_matches(node, matcher, metadata_lookup)
1519 if node_capture is None:
1520 return None
1521 all_captures = {**all_captures, **node_capture}
1522 return all_captures
1523 else:
1524 return _node_matches(node, matcher, metadata_lookup)
1527def _construct_metadata_fetcher_null() -> (
1528 Callable[[meta.ProviderT, libcst.CSTNode], object]
1529):
1530 def _fetch(provider: meta.ProviderT, node: libcst.CSTNode) -> NoReturn:
1531 raise LookupError(
1532 f"{provider.__name__} is not resolved; did you forget a MetadataWrapper?"
1533 )
1535 return _fetch
1538def _construct_metadata_fetcher_dependent(
1539 dependent_class: libcst.MetadataDependent,
1540) -> Callable[[meta.ProviderT, libcst.CSTNode], object]:
1541 def _fetch(provider: meta.ProviderT, node: libcst.CSTNode) -> object:
1542 return dependent_class.get_metadata(provider, node, _METADATA_MISSING_SENTINEL)
1544 return _fetch
1547def _construct_metadata_fetcher_wrapper(
1548 wrapper: libcst.MetadataWrapper,
1549) -> Callable[[meta.ProviderT, libcst.CSTNode], object]:
1550 metadata: Dict[meta.ProviderT, Mapping[libcst.CSTNode, object]] = {}
1552 def _fetch(provider: meta.ProviderT, node: libcst.CSTNode) -> object:
1553 if provider not in metadata:
1554 metadata[provider] = wrapper.resolve(provider)
1556 node_metadata = metadata[provider].get(node, _METADATA_MISSING_SENTINEL)
1557 if isinstance(node_metadata, LazyValue):
1558 node_metadata = node_metadata()
1560 return node_metadata
1562 return _fetch
1565def extract(
1566 node: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode],
1567 matcher: BaseMatcherNode,
1568 *,
1569 metadata_resolver: Optional[
1570 Union[libcst.MetadataDependent, libcst.MetadataWrapper]
1571 ] = None,
1572) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]:
1573 """
1574 Given an arbitrary node from a LibCST tree, and an arbitrary matcher, returns
1575 a dictionary of extracted children of the tree if the node matches the shape defined
1576 by the matcher. Note that the node can also be a :class:`~libcst.RemovalSentinel` or
1577 a :class:`~libcst.MaybeSentinel` in order to use extract directly on transform results
1578 and node attributes. In these cases, :func:`extract` will always return ``None``.
1580 If the node matches the shape defined by the matcher, the return will be a dictionary
1581 whose keys are defined by the :func:`SaveMatchedNode` name parameter, and the values
1582 will be the node or sequence that was present at that location in the shape defined
1583 by the matcher. In the case of multiple :func:`SaveMatchedNode` matches with the
1584 same name, parent nodes will take prioirity over child nodes, and nodes later in
1585 sequences will take priority over nodes earlier in sequences.
1587 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`,
1588 or a :class:`OneOf`/:class:`AllOf` special matcher. It cannot be a
1589 :class:`MatchIfTrue` or a :func:`DoesNotMatch` matcher since these are redundant.
1590 It cannot be a :class:`AtLeastN` or :class:`AtMostN` matcher because these types are
1591 wildcards which can only be used inside sequences.
1592 """
1593 if isinstance(node, RemovalSentinel):
1594 # We can't possibly match on a removal sentinel, so it doesn't match.
1595 return None
1596 if isinstance(matcher, (AtLeastN, AtMostN, MatchIfTrue, _BaseMetadataMatcher)):
1597 # We can't match this, since these matchers are forbidden at top level.
1598 # These are not subclasses of BaseMatcherNode, but in the case that the
1599 # user is not using type checking, this should still behave correctly.
1600 return None
1602 if metadata_resolver is None:
1603 fetcher = _construct_metadata_fetcher_null()
1604 elif isinstance(metadata_resolver, libcst.MetadataWrapper):
1605 fetcher = _construct_metadata_fetcher_wrapper(metadata_resolver)
1606 else:
1607 fetcher = _construct_metadata_fetcher_dependent(metadata_resolver)
1609 return _matches(node, matcher, fetcher)
1612def matches(
1613 node: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode],
1614 matcher: BaseMatcherNode,
1615 *,
1616 metadata_resolver: Optional[
1617 Union[libcst.MetadataDependent, libcst.MetadataWrapper]
1618 ] = None,
1619) -> bool:
1620 """
1621 Given an arbitrary node from a LibCST tree, and an arbitrary matcher, returns
1622 ``True`` if the node matches the shape defined by the matcher. Note that the node
1623 can also be a :class:`~libcst.RemovalSentinel` or a :class:`~libcst.MaybeSentinel`
1624 in order to use matches directly on transform results and node attributes. In these
1625 cases, :func:`matches` will always return ``False``.
1627 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`,
1628 or a :class:`OneOf`/:class:`AllOf` special matcher. It cannot be a
1629 :class:`MatchIfTrue` or a :func:`DoesNotMatch` matcher since these are redundant.
1630 It cannot be a :class:`AtLeastN` or :class:`AtMostN` matcher because these types
1631 are wildcards which can only be used inside sequences.
1632 """
1633 return extract(node, matcher, metadata_resolver=metadata_resolver) is not None
1636class _FindAllVisitor(libcst.CSTVisitor):
1637 def __init__(
1638 self,
1639 matcher: Union[
1640 BaseMatcherNode,
1641 MatchIfTrue[libcst.CSTNode],
1642 _BaseMetadataMatcher,
1643 _InverseOf[
1644 Union[
1645 BaseMatcherNode,
1646 MatchIfTrue[libcst.CSTNode],
1647 _BaseMetadataMatcher,
1648 ]
1649 ],
1650 ],
1651 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object],
1652 ) -> None:
1653 self.matcher = matcher
1654 self.metadata_lookup = metadata_lookup
1655 self.found_nodes: List[libcst.CSTNode] = []
1656 self.extracted_nodes: List[
1657 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]
1658 ] = []
1660 def on_visit(self, node: libcst.CSTNode) -> bool:
1661 match = _matches(node, self.matcher, self.metadata_lookup)
1662 if match is not None:
1663 self.found_nodes.append(node)
1664 self.extracted_nodes.append(match)
1665 return True
1668def _find_or_extract_all(
1669 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper],
1670 matcher: Union[
1671 BaseMatcherNode,
1672 MatchIfTrue[libcst.CSTNode],
1673 _BaseMetadataMatcher,
1674 # The inverse clause is left off of the public functions `findall` and
1675 # `extractall` because we play a dirty trick. We lie to the typechecker
1676 # that `DoesNotMatch` returns identity, so the public functions don't
1677 # need to be aware of inverses. If we could represent predicate logic
1678 # in python types we could get away with this, but that's not the state
1679 # of things right now.
1680 _InverseOf[
1681 Union[
1682 BaseMatcherNode,
1683 MatchIfTrue[libcst.CSTNode],
1684 _BaseMetadataMatcher,
1685 ]
1686 ],
1687 ],
1688 *,
1689 metadata_resolver: Optional[
1690 Union[libcst.MetadataDependent, libcst.MetadataWrapper]
1691 ] = None,
1692) -> Tuple[
1693 Sequence[libcst.CSTNode],
1694 Sequence[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]],
1695]:
1696 if isinstance(tree, (RemovalSentinel, MaybeSentinel)):
1697 # We can't possibly match on a removal sentinel, so it doesn't match.
1698 return [], []
1699 if isinstance(matcher, (AtLeastN, AtMostN)):
1700 # We can't match this, since these matchers are forbidden at top level.
1701 # These are not subclasses of BaseMatcherNode, but in the case that the
1702 # user is not using type checking, this should still behave correctly.
1703 return [], []
1705 if isinstance(tree, meta.MetadataWrapper) and metadata_resolver is None:
1706 # Provide a convenience for calling findall directly on a MetadataWrapper.
1707 metadata_resolver = tree
1709 if metadata_resolver is None:
1710 fetcher = _construct_metadata_fetcher_null()
1711 elif isinstance(metadata_resolver, libcst.MetadataWrapper):
1712 fetcher = _construct_metadata_fetcher_wrapper(metadata_resolver)
1713 else:
1714 fetcher = _construct_metadata_fetcher_dependent(metadata_resolver)
1716 finder = _FindAllVisitor(matcher, fetcher)
1717 tree.visit(finder)
1718 return finder.found_nodes, finder.extracted_nodes
1721def findall(
1722 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper],
1723 matcher: Union[BaseMatcherNode, MatchIfTrue[libcst.CSTNode], _BaseMetadataMatcher],
1724 *,
1725 metadata_resolver: Optional[
1726 Union[libcst.MetadataDependent, libcst.MetadataWrapper]
1727 ] = None,
1728) -> Sequence[libcst.CSTNode]:
1729 """
1730 Given an arbitrary node from a LibCST tree and an arbitrary matcher, iterates
1731 over that node and all children returning a sequence of all child nodes that
1732 match the given matcher. Note that the tree can also be a
1733 :class:`~libcst.RemovalSentinel` or a :class:`~libcst.MaybeSentinel`
1734 in order to use findall directly on transform results and node attributes. In these
1735 cases, :func:`findall` will always return an empty sequence. Note also that
1736 instead of a LibCST tree, you can instead pass in a
1737 :class:`~libcst.metadata.MetadataWrapper`. This mirrors the fact that you can
1738 call ``visit`` on a :class:`~libcst.metadata.MetadataWrapper` in order to iterate
1739 over it with a transform. If you provide a wrapper for the tree and do not set
1740 the ``metadata_resolver`` parameter specifically, it will automatically be set
1741 to the wrapper for you.
1743 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`,
1744 or a :class:`OneOf`/:class:`AllOf` special matcher. Unlike :func:`matches`, it can
1745 also be a :class:`MatchIfTrue` or :func:`DoesNotMatch` matcher, since we are
1746 traversing the tree looking for matches. It cannot be a :class:`AtLeastN` or
1747 :class:`AtMostN` matcher because these types are wildcards which can only be used
1748 inside sequences.
1749 """
1750 nodes, _ = _find_or_extract_all(tree, matcher, metadata_resolver=metadata_resolver)
1751 return nodes
1754def extractall(
1755 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper],
1756 matcher: Union[BaseMatcherNode, MatchIfTrue[libcst.CSTNode], _BaseMetadataMatcher],
1757 *,
1758 metadata_resolver: Optional[
1759 Union[libcst.MetadataDependent, libcst.MetadataWrapper]
1760 ] = None,
1761) -> Sequence[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]:
1762 """
1763 Given an arbitrary node from a LibCST tree and an arbitrary matcher, iterates
1764 over that node and all children returning a sequence of dictionaries representing
1765 the saved and extracted children specified by :func:`SaveMatchedNode` for each
1766 match found in the tree. This is analogous to running a :func:`findall` over a
1767 tree, then running :func:`extract` with the same matcher over each of the returned
1768 nodes. Note that the tree can also be a :class:`~libcst.RemovalSentinel` or a
1769 :class:`~libcst.MaybeSentinel` in order to use extractall directly on transform
1770 results and node attributes. In these cases, :func:`extractall` will always
1771 return an empty sequence. Note also that instead of a LibCST tree, you can
1772 instead pass in a :class:`~libcst.metadata.MetadataWrapper`. This mirrors the
1773 fact that you can call ``visit`` on a :class:`~libcst.metadata.MetadataWrapper`
1774 in order to iterate over it with a transform. If you provide a wrapper for the
1775 tree and do not set the ``metadata_resolver`` parameter specifically, it will
1776 automatically be set to the wrapper for you.
1778 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`,
1779 or a :class:`OneOf`/:class:`AllOf` special matcher. Unlike :func:`matches`, it can
1780 also be a :class:`MatchIfTrue` or :func:`DoesNotMatch` matcher, since we are
1781 traversing the tree looking for matches. It cannot be a :class:`AtLeastN` or
1782 :class:`AtMostN` matcher because these types are wildcards which can only be usedi
1783 inside sequences.
1784 """
1785 _, extractions = _find_or_extract_all(
1786 tree, matcher, metadata_resolver=metadata_resolver
1787 )
1788 return extractions
1791class _ReplaceTransformer(libcst.CSTTransformer):
1792 def __init__(
1793 self,
1794 matcher: Union[
1795 BaseMatcherNode,
1796 MatchIfTrue[libcst.CSTNode],
1797 _BaseMetadataMatcher,
1798 _InverseOf[
1799 Union[
1800 BaseMatcherNode,
1801 MatchIfTrue[libcst.CSTNode],
1802 _BaseMetadataMatcher,
1803 ]
1804 ],
1805 ],
1806 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object],
1807 replacement: Union[
1808 MaybeSentinel,
1809 RemovalSentinel,
1810 libcst.CSTNode,
1811 Callable[
1812 [
1813 libcst.CSTNode,
1814 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]],
1815 ],
1816 Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode],
1817 ],
1818 ],
1819 ) -> None:
1820 self.matcher = matcher
1821 self.metadata_lookup = metadata_lookup
1822 self.replacement: Callable[
1823 [
1824 libcst.CSTNode,
1825 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]],
1826 ],
1827 Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode],
1828 ]
1830 if inspect.isfunction(replacement):
1831 self.replacement = replacement
1832 elif isinstance(replacement, (MaybeSentinel, RemovalSentinel)):
1833 self.replacement = lambda node, matches: replacement
1834 else:
1835 # pyre-ignore We know this is a CSTNode.
1836 self.replacement = lambda node, matches: replacement.deep_clone()
1837 # We run into a really weird problem here, where we need to run the match
1838 # and extract step on the original node in order for metadata to work.
1839 # However, if we do that, then using things like `deep_replace` will fail
1840 # since any extracted nodes are the originals, not the updates and LibCST
1841 # does replacement by identity for safety reasons. If we try to run the
1842 # match and extract step on the updated node (or twice, once for the match
1843 # and once for the extract), it will fail to extract if any metadata-based
1844 # matchers are used. So, we try to compromise with the best of both worlds.
1845 # We track all node updates, and when we send the extracted nodes to the
1846 # replacement callable, we look up the original nodes and replace them with
1847 # updated nodes. In the case that an update made the node no-longer exist,
1848 # we act as if there was not a match (because in reality, there would not
1849 # have been if we had run the matcher on the update).
1850 self.node_lut: Dict[libcst.CSTNode, libcst.CSTNode] = {}
1852 def _node_translate(
1853 self, node_or_sequence: Union[libcst.CSTNode, Sequence[libcst.CSTNode]]
1854 ) -> Union[libcst.CSTNode, Sequence[libcst.CSTNode]]:
1855 if isinstance(node_or_sequence, Sequence):
1856 return tuple(self.node_lut[node] for node in node_or_sequence)
1857 else:
1858 return self.node_lut[node_or_sequence]
1860 def _extraction_translate(
1861 self, extracted: Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]
1862 ) -> Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]:
1863 return {key: self._node_translate(val) for key, val in extracted.items()}
1865 def on_leave(
1866 self, original_node: libcst.CSTNode, updated_node: libcst.CSTNode
1867 ) -> Union[libcst.CSTNode, MaybeSentinel, RemovalSentinel]:
1868 # Track original to updated node mapping for this node.
1869 self.node_lut[original_node] = updated_node
1871 # This gets complicated. We need to do the match on the original node,
1872 # but we want to do the extraction on the updated node. This is so
1873 # metadata works properly in matchers. So, if we get a match, we fix
1874 # up the nodes in the match and return that to the replacement lambda.
1875 extracted = _matches(original_node, self.matcher, self.metadata_lookup)
1876 if extracted is not None:
1877 try:
1878 # Attempt to do a translation from original to updated node.
1879 extracted = self._extraction_translate(extracted)
1880 except KeyError:
1881 # One of the nodes we looked up doesn't exist anymore, this
1882 # is no longer a match. This can happen if a child node was
1883 # modified, making this original match not applicable anymore.
1884 extracted = None
1885 if extracted is not None:
1886 # We're replacing this node entirely, so don't save the original
1887 # updated node. We don't want this to be part of a parent match
1888 # since we can't guarantee that the update matches anymore.
1889 del self.node_lut[original_node]
1890 return self.replacement(updated_node, extracted)
1891 return updated_node
1894def replace(
1895 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper],
1896 matcher: Union[BaseMatcherNode, MatchIfTrue[libcst.CSTNode], _BaseMetadataMatcher],
1897 replacement: Union[
1898 MaybeSentinel,
1899 RemovalSentinel,
1900 libcst.CSTNode,
1901 Callable[
1902 [
1903 libcst.CSTNode,
1904 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]],
1905 ],
1906 Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode],
1907 ],
1908 ],
1909 *,
1910 metadata_resolver: Optional[
1911 Union[libcst.MetadataDependent, libcst.MetadataWrapper]
1912 ] = None,
1913) -> Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode]:
1914 """
1915 Given an arbitrary node from a LibCST tree and an arbitrary matcher, iterates
1916 over that node and all children and replaces each node that matches the supplied
1917 matcher with a supplied replacement. Note that the replacement can either be a
1918 valid node type, or a callable which takes the matched node and a dictionary of
1919 any extracted child values and returns a valid node type. If you provide a
1920 valid LibCST node type, :func:`replace` will replace every node that matches
1921 the supplied matcher with the replacement node. If you provide a callable,
1922 :func:`replace` will run :func:`extract` over all matched nodes and call the
1923 callable with both the node that should be replaced and the dictionary returned
1924 by :func:`extract`. Under all circumstances a new tree is returned.
1925 :func:`extract` should be viewed as a short-cut to writing a transform which
1926 also returns a new tree even when no changes are applied.
1928 Note that the tree can also be a :class:`~libcst.RemovalSentinel` or a
1929 :class:`~libcst.MaybeSentinel` in order to use replace directly on transform
1930 results and node attributes. In these cases, :func:`replace` will return the
1931 same :class:`~libcst.RemovalSentinel` or :class:`~libcst.MaybeSentinel`.
1932 Note also that instead of a LibCST tree, you can instead pass in a
1933 :class:`~libcst.metadata.MetadataWrapper`. This mirrors the fact that you can
1934 call ``visit`` on a :class:`~libcst.metadata.MetadataWrapper` in order to
1935 iterate over it with a transform. If you provide a wrapper for the tree and
1936 do not set the ``metadata_resolver`` parameter specifically, it will
1937 automatically be set to the wrapper for you.
1939 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`,
1940 or a :class:`OneOf`/:class:`AllOf` special matcher. Unlike :func:`matches`, it can
1941 also be a :class:`MatchIfTrue` or :func:`DoesNotMatch` matcher, since we are
1942 traversing the tree looking for matches. It cannot be a :class:`AtLeastN` or
1943 :class:`AtMostN` matcher because these types are wildcards which can only be usedi
1944 inside sequences.
1945 """
1946 if isinstance(tree, (RemovalSentinel, MaybeSentinel)):
1947 # We can't do any replacements on this, so return the tree exactly.
1948 return tree
1949 if isinstance(matcher, (AtLeastN, AtMostN)):
1950 # We can't match this, since these matchers are forbidden at top level.
1951 # These are not subclasses of BaseMatcherNode, but in the case that the
1952 # user is not using type checking, this should still behave correctly.
1953 if isinstance(tree, libcst.CSTNode):
1954 return tree.deep_clone()
1955 elif isinstance(tree, meta.MetadataWrapper):
1956 return tree.module.deep_clone()
1957 else:
1958 raise Exception("Logic error!")
1960 if isinstance(tree, meta.MetadataWrapper) and metadata_resolver is None:
1961 # Provide a convenience for calling replace directly on a MetadataWrapper.
1962 metadata_resolver = tree
1964 if metadata_resolver is None:
1965 fetcher = _construct_metadata_fetcher_null()
1966 elif isinstance(metadata_resolver, libcst.MetadataWrapper):
1967 fetcher = _construct_metadata_fetcher_wrapper(metadata_resolver)
1968 else:
1969 fetcher = _construct_metadata_fetcher_dependent(metadata_resolver)
1971 replacer = _ReplaceTransformer(matcher, fetcher, replacement)
1972 new_tree = tree.visit(replacer)
1973 if isinstance(new_tree, FlattenSentinel):
1974 # The above transform never returns FlattenSentinel, so this isn't possible
1975 raise Exception("Logic error, cannot get a FlattenSentinel here!")
1976 return new_tree