Source code for libcst.matchers._decorators

# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

from typing import Callable, TypeVar

from libcst.matchers._matcher_base import BaseMatcherNode

_CSTVisitFuncT = TypeVar("_CSTVisitFuncT")


VISIT_POSITIVE_MATCHER_ATTR: str = "_call_if_inside_matcher"
VISIT_NEGATIVE_MATCHER_ATTR: str = "_call_if_not_inside_matcher"
CONSTRUCTED_VISIT_MATCHER_ATTR: str = "_visit_matcher"
CONSTRUCTED_LEAVE_MATCHER_ATTR: str = "_leave_matcher"


[docs] def call_if_inside( matcher: BaseMatcherNode, # pyre-fixme[34]: `Variable[_CSTVisitFuncT]` isn't present in the function's parameters. ) -> Callable[[_CSTVisitFuncT], _CSTVisitFuncT]: """ A decorator for visit and leave methods inside a :class:`MatcherDecoratableTransformer` or a :class:`MatcherDecoratableVisitor`. A method that is decorated with this decorator will only be called if it or one of its parents matches the supplied matcher. Use this to selectively gate visit and leave methods to be called only when inside of another relevant node. Note that this works for both node and attribute methods, so you can decorate a ``visit_<Node>`` or a ``visit_<Node>_<Attr>`` method. """ def inner(original: _CSTVisitFuncT) -> _CSTVisitFuncT: setattr( original, VISIT_POSITIVE_MATCHER_ATTR, [*getattr(original, VISIT_POSITIVE_MATCHER_ATTR, []), matcher], ) return original return inner
[docs] def call_if_not_inside( matcher: BaseMatcherNode, # pyre-fixme[34]: `Variable[_CSTVisitFuncT]` isn't present in the function's parameters. ) -> Callable[[_CSTVisitFuncT], _CSTVisitFuncT]: """ A decorator for visit and leave methods inside a :class:`MatcherDecoratableTransformer` or a :class:`MatcherDecoratableVisitor`. A method that is decorated with this decorator will only be called if it or one of its parents does not match the supplied matcher. Use this to selectively gate visit and leave methods to be called only when outside of another relevant node. Note that this works for both node and attribute methods, so you can decorate a ``visit_<Node>`` or a ``visit_<Node>_<Attr>`` method. """ def inner(original: _CSTVisitFuncT) -> _CSTVisitFuncT: setattr( original, VISIT_NEGATIVE_MATCHER_ATTR, [*getattr(original, VISIT_NEGATIVE_MATCHER_ATTR, []), matcher], ) return original return inner
# pyre-fixme[34]: `Variable[_CSTVisitFuncT]` isn't present in the function's parameters.
[docs] def visit(matcher: BaseMatcherNode) -> Callable[[_CSTVisitFuncT], _CSTVisitFuncT]: """ A decorator that allows a method inside a :class:`MatcherDecoratableTransformer` or a :class:`MatcherDecoratableVisitor` visitor to be called when visiting a node that matches the provided matcher. Note that you can use this in combination with :func:`call_if_inside` and :func:`call_if_not_inside` decorators. Unlike explicit ``visit_<Node>`` and ``leave_<Node>`` methods, functions decorated with this decorator cannot stop child traversal by returning ``False``. Decorated visit functions should always have a return annotation of ``None``. There is no restriction on the number of visit decorators allowed on a method. There is also no restriction on the number of methods that may be decorated with the same matcher. When multiple visit decorators are found on the same method, they act as a simple or, and the method will be called when any one of the contained matches is ``True``. """ def inner(original: _CSTVisitFuncT) -> _CSTVisitFuncT: setattr( original, CONSTRUCTED_VISIT_MATCHER_ATTR, [*getattr(original, CONSTRUCTED_VISIT_MATCHER_ATTR, []), matcher], ) return original return inner
# pyre-fixme[34]: `Variable[_CSTVisitFuncT]` isn't present in the function's parameters.
[docs] def leave(matcher: BaseMatcherNode) -> Callable[[_CSTVisitFuncT], _CSTVisitFuncT]: """ A decorator that allows a method inside a :class:`MatcherDecoratableTransformer` or a :class:`MatcherDecoratableVisitor` visitor to be called when leaving a node that matches the provided matcher. Note that you can use this in combination with :func:`call_if_inside` and :func:`call_if_not_inside` decorators. There is no restriction on the number of leave decorators allowed on a method. There is also no restriction on the number of methods that may be decorated with the same matcher. When multiple leave decorators are found on the same method, they act as a simple or, and the method will be called when any one of the contained matches is ``True``. """ def inner(original: _CSTVisitFuncT) -> _CSTVisitFuncT: setattr( original, CONSTRUCTED_LEAVE_MATCHER_ATTR, [*getattr(original, CONSTRUCTED_LEAVE_MATCHER_ATTR, []), matcher], ) return original return inner