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
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)
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)
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
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)