Example #1
0
    def on_leave(
        self, original_node: _CSTNodeT, updated_node: _CSTNodeT
    ) -> Union[_CSTNodeT, cst.RemovalSentinel]:
        # First, evaluate whether this current function has a decorator on it.
        if _should_allow_visit(
            self._matchers, getattr(self, f"leave_{type(original_node).__name__}", None)
        ):
            retval = CSTTransformer.on_leave(self, original_node, updated_node)
        else:
            retval = updated_node

        # Now, call any visitors that were hooked using a leave decorator.
        for matcher, leave_funcs in reversed(list(self._extra_leave_funcs.items())):
            if not matches(original_node, matcher):
                continue
            for leave_func in leave_funcs:
                if _should_allow_visit(self._matchers, leave_func) and isinstance(
                    retval, cst.CSTNode
                ):
                    retval = leave_func(original_node, retval)

        # Now, see if we have any matchers we should deactivate.
        self._matchers = _leave_matchers(self._matchers, original_node)

        # pyre-ignore The return value of on_leave is subtly wrong in that we can
        # actually return any value that passes this node's parent's constructor
        # validation. Fixing this is beyond the scope of this file, and would involve
        # forcing a lot of ensure_type() checks across the codebase.
        return retval
Example #2
0
def _visit_constructed_funcs(
    visit_funcs: Dict[BaseMatcherNode, Sequence[Callable[[cst.CSTNode], None]]],
    all_matchers: Dict[BaseMatcherNode, Optional[cst.CSTNode]],
    node: cst.CSTNode,
) -> None:
    for matcher, visit_funcs in visit_funcs.items():
        if matches(node, matcher):
            for visit_func in visit_funcs:
                if _should_allow_visit(all_matchers, visit_func):
                    visit_func(node)
Example #3
0
 def matches(
     self,
     node: Union[cst.MaybeSentinel, cst.RemovalSentinel, cst.CSTNode],
     matcher: BaseMatcherNode,
 ) -> bool:
     """
     A convenience method to call :func:`~libcst.matchers.matches` without requiring
     an explicit parameter for metadata. Since our instance is an instance of
     :class:`libcst.MetadataDependent`, we work as a metadata resolver. Please see
     documentation for :func:`~libcst.matchers.matches` as it is identical to this
     function.
     """
     return matches(node, matcher, metadata_resolver=self)
Example #4
0
def _visit_matchers(
    matchers: Dict[BaseMatcherNode, Optional[cst.CSTNode]], node: cst.CSTNode
) -> Dict[BaseMatcherNode, Optional[cst.CSTNode]]:
    new_matchers: Dict[BaseMatcherNode, Optional[cst.CSTNode]] = {}
    for matcher, existing_node in matchers.items():
        # We don't care about visiting matchers that are already true.
        if existing_node is None and matches(node, matcher):
            # This node matches! Remember which node it was so we can
            # cancel it later.
            new_matchers[matcher] = node
        else:
            new_matchers[matcher] = existing_node
    return new_matchers
Example #5
0
    def on_leave(self, original_node: cst.CSTNode) -> None:
        # First, evaluate whether this current function has a decorator on it.
        if _should_allow_visit(
            self._matchers, getattr(self, f"leave_{type(original_node).__name__}", None)
        ):
            CSTVisitor.on_leave(self, original_node)

        # Now, call any visitors that were hooked using a leave decorator.
        for matcher, leave_funcs in reversed(list(self._extra_leave_funcs.items())):
            if not matches(original_node, matcher):
                continue
            for leave_func in leave_funcs:
                if _should_allow_visit(self._matchers, leave_func):
                    leave_func(original_node)

        # Now, see if we have any matchers we should deactivate.
        self._matchers = _leave_matchers(self._matchers, original_node)