Ejemplo n.º 1
0
    def test_extract_simple(self) -> None:
        # Verify true behavior
        expression = cst.parse_expression("a + b[c], d(e, f * g)")
        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.Element(
                    m.BinaryOperation(
                        left=m.SaveMatchedNode(m.Name(), "left"))),
                m.Element(m.Call()),
            ]),
        )
        extracted_node = cst.ensure_type(
            cst.ensure_type(expression, cst.Tuple).elements[0].value,
            cst.BinaryOperation,
        ).left
        self.assertEqual(nodes, {"left": extracted_node})

        # Verify false behavior
        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.Element(
                    m.BinaryOperation(
                        left=m.SaveMatchedNode(m.Subscript(), "left"))),
                m.Element(m.Call()),
            ]),
        )
        self.assertIsNone(nodes)
Ejemplo n.º 2
0
    def test_extract_sequence_element(self) -> None:
        # Verify true behavior
        expression = cst.parse_expression("a + b[c], d(e, f * g, h.i.j)")
        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.DoNotCare(),
                m.Element(
                    m.Call(args=[m.SaveMatchedNode(m.ZeroOrMore(), "args")])),
            ]),
        )
        extracted_seq = cst.ensure_type(
            cst.ensure_type(expression, cst.Tuple).elements[1].value,
            cst.Call).args
        self.assertEqual(nodes, {"args": extracted_seq})

        # Verify false behavior
        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.DoNotCare(),
                m.Element(
                    m.Call(args=[
                        m.SaveMatchedNode(m.ZeroOrMore(m.Arg(m.Subscript())),
                                          "args")
                    ])),
            ]),
        )
        self.assertIsNone(nodes)
Ejemplo n.º 3
0
class UnhashableListTransformer(NoqaAwareTransformer):
    @m.call_if_inside(
        m.Call(
            func=m.OneOf(m.Name(value="set"), m.Name(value="frozenset")),
            args=[m.Arg(value=m.OneOf(m.List(), m.Tuple(), m.Set()))],
        )
        | m.Set()  # noqa: W503
    )
    @m.leave(m.List() | m.Set() | m.Tuple())
    def convert_list_arg(
        self, _, updated_node: Union[cst.Set, cst.List,
                                     cst.Tuple]) -> cst.BaseExpression:
        modified_elements = convert_lists_to_tuples(updated_node.elements)
        return updated_node.with_changes(elements=modified_elements)
Ejemplo n.º 4
0
    def test_extract_predicates(self) -> None:
        expression = cst.parse_expression("a + b[c], d(e, f * g)")
        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.Element(
                    m.BinaryOperation(
                        left=m.SaveMatchedNode(m.Name(), "left"))),
                m.Element(
                    m.Call(func=m.SaveMatchedNode(m.Name(), "func")
                           | m.SaveMatchedNode(m.Attribute(), "attr"))),
            ]),
        )
        extracted_node_left = cst.ensure_type(
            cst.ensure_type(expression, cst.Tuple).elements[0].value,
            cst.BinaryOperation,
        ).left
        extracted_node_func = cst.ensure_type(
            cst.ensure_type(expression, cst.Tuple).elements[1].value,
            cst.Call).func
        self.assertEqual(nodes, {
            "left": extracted_node_left,
            "func": extracted_node_func
        })

        expression = cst.parse_expression("a + b[c], d.z(e, f * g)")
        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.Element(
                    m.BinaryOperation(
                        left=m.SaveMatchedNode(m.Name(), "left"))),
                m.Element(
                    m.Call(func=m.SaveMatchedNode(m.Name(), "func")
                           | m.SaveMatchedNode(m.Attribute(), "attr"))),
            ]),
        )
        extracted_node_left = cst.ensure_type(
            cst.ensure_type(expression, cst.Tuple).elements[0].value,
            cst.BinaryOperation,
        ).left
        extracted_node_attr = cst.ensure_type(
            cst.ensure_type(expression, cst.Tuple).elements[1].value,
            cst.Call).func
        self.assertEqual(nodes, {
            "left": extracted_node_left,
            "attr": extracted_node_attr
        })
Ejemplo n.º 5
0
    def test_extract_metadata(self) -> None:
        # Verify true behavior
        module = cst.parse_module("a + b[c], d(e, f * g)")
        wrapper = cst.MetadataWrapper(module)
        expression = cst.ensure_type(
            cst.ensure_type(wrapper.module.body[0],
                            cst.SimpleStatementLine).body[0],
            cst.Expr,
        ).value

        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.Element(
                    m.BinaryOperation(left=m.Name(metadata=m.SaveMatchedNode(
                        m.MatchMetadata(
                            meta.PositionProvider,
                            self._make_coderange((1, 0), (1, 1)),
                        ),
                        "left",
                    )))),
                m.Element(m.Call()),
            ]),
            metadata_resolver=wrapper,
        )
        extracted_node = cst.ensure_type(
            cst.ensure_type(expression, cst.Tuple).elements[0].value,
            cst.BinaryOperation,
        ).left
        self.assertEqual(nodes, {"left": extracted_node})

        # Verify false behavior
        nodes = m.extract(
            expression,
            m.Tuple(elements=[
                m.Element(
                    m.BinaryOperation(left=m.Name(metadata=m.SaveMatchedNode(
                        m.MatchMetadata(
                            meta.PositionProvider,
                            self._make_coderange((1, 0), (1, 2)),
                        ),
                        "left",
                    )))),
                m.Element(m.Call()),
            ]),
            metadata_resolver=wrapper,
        )
        self.assertIsNone(nodes)
Ejemplo n.º 6
0
    def collect_targets(
        self, stack: Tuple[cst.BaseExpression, ...]
    ) -> Tuple[
        List[cst.BaseExpression], Dict[cst.BaseExpression, List[cst.BaseExpression]]
    ]:
        targets = {}
        operands = []

        for operand in stack:
            if m.matches(
                operand, m.Call(func=m.DoNotCare(), args=[m.Arg(), m.Arg(~m.Tuple())])
            ):
                call = cst.ensure_type(operand, cst.Call)
                if not QualifiedNameProvider.has_name(self, call, _ISINSTANCE):
                    operands.append(operand)
                    continue

                target, match = call.args[0].value, call.args[1].value
                for possible_target in targets:
                    if target.deep_equals(possible_target):
                        targets[possible_target].append(match)
                        break
                else:
                    operands.append(target)
                    targets[target] = [match]
            else:
                operands.append(operand)

        return operands, targets
Ejemplo n.º 7
0
    def __extract_names_multi_assign(self, elements):
        # Add self vars. in tuple assignments, e.g. self.x, self.y = 1, 2
        # Adds variables in tuple(s) in multiple assignments, e.g. a, (b, c) = 1, (2, 3)
        names: List[cst.Name] = []
        i = 0
        while i < len(elements):
            if match.matches(
                    elements[i],
                    match.Element(value=match.Name(value=match.DoNotCare()))):
                names.append(elements[i].value)
            elif match.matches(
                    elements[i],
                    match.Element(value=match.Attribute(attr=match.Name(
                        value=match.DoNotCare())))):
                names.append(elements[i].value)
            elif match.matches(
                    elements[i],
                    match.Element(value=match.Tuple(
                        elements=match.DoNotCare()))):
                elements.extend(
                    match.findall(
                        elements[i].value,
                        match.Element(value=match.OneOf(
                            match.Attribute(attr=match.Name(
                                value=match.DoNotCare())),
                            match.Name(value=match.DoNotCare())))))
            i += 1

        return names
Ejemplo n.º 8
0
    def process_variable(self, node: Union[cst.BaseExpression,
                                           cst.BaseAssignTargetExpression]):

        if m.matches(node, m.Name()):
            node = cst.ensure_type(node, cst.Name)

            if self.class_stack and not self.function_stack:
                self.class_stack[-1].variables.append(node.value)
            else:
                self.info.variables.append(node.value)

        elif m.matches(node, m.Attribute()):
            node = cst.ensure_type(node, cst.Attribute)

            splitted_attributes = split_attribute(node)

            if splitted_attributes[
                    0] == 'self' and self.class_stack and self.function_stack and len(
                        splitted_attributes) > 1:
                self.class_stack[-1].variables.append(splitted_attributes[1])
            else:
                self.info.variables.append(splitted_attributes[0])

        elif m.matches(node, m.Tuple()):
            node = cst.ensure_type(node, cst.Tuple)
            for el in node.elements:
                self.process_variable(el.value)

        else:
            pass
Ejemplo n.º 9
0
    def leave_Yield(self, original_node, updated_node) -> cst.BaseExpression:
        append = parse_expr(f'{self.ret_var}.append()')
        yield_val = updated_node.value

        # If original expr was "yield a, b" then yield_val compiles to
        # "a, b" (i.e. no parens) which errors if directly inserted into
        # foo.append(a, b). So we ensure that the tuple has parentheses.
        if m.matches(yield_val, m.Tuple()):
            yield_val = yield_val.with_changes(lpar=[cst.LeftParen()],
                                               rpar=[cst.RightParen()])

        return append.with_changes(args=[cst.Arg(yield_val)])
Ejemplo n.º 10
0
 def test_extract_tautology(self) -> None:
     expression = cst.parse_expression("a + b[c], d(e, f * g)")
     nodes = m.extract(
         expression,
         m.SaveMatchedNode(
             m.Tuple(elements=[
                 m.Element(m.BinaryOperation()),
                 m.Element(m.Call())
             ]),
             name="node",
         ),
     )
     self.assertEqual(nodes, {"node": expression})
Ejemplo n.º 11
0
 def visit_AugAssign(self, node: cst.AugAssign) -> bool:
     if m.matches(
             node,
             m.AugAssign(
                 target=m.Name("__all__"),
                 operator=m.AddAssign(),
                 value=m.List() | m.Tuple(),
             ),
     ):
         value = node.value
         if isinstance(value, (cst.List, cst.Tuple)):
             self._is_assigned_export.add(value)
         return True
     return False
Ejemplo n.º 12
0
 def test_extract_sequence(self) -> None:
     expression = cst.parse_expression("a + b[c], d(e, f * g, h.i.j)")
     nodes = m.extract(
         expression,
         m.Tuple(elements=[
             m.DoNotCare(),
             m.Element(
                 m.Call(args=m.SaveMatchedNode([m.ZeroOrMore()], "args"))),
         ]),
     )
     extracted_seq = cst.ensure_type(
         cst.ensure_type(expression, cst.Tuple).elements[1].value,
         cst.Call).args
     self.assertEqual(nodes, {"args": extracted_seq})
    def visit_Call(self, node: cst.Call) -> None:
        if m.matches(
                node,
                m.Call(
                    func=m.Name("list") | m.Name("set") | m.Name("dict"),
                    args=[m.Arg(value=m.GeneratorExp() | m.ListComp())],
                ),
        ):
            call_name = cst.ensure_type(node.func, cst.Name).value

            if m.matches(node.args[0].value, m.GeneratorExp()):
                exp = cst.ensure_type(node.args[0].value, cst.GeneratorExp)
                message_formatter = UNNECESSARY_GENERATOR
            else:
                exp = cst.ensure_type(node.args[0].value, cst.ListComp)
                message_formatter = UNNECESSARY_LIST_COMPREHENSION

            replacement = None
            if call_name == "list":
                replacement = node.deep_replace(
                    node, cst.ListComp(elt=exp.elt, for_in=exp.for_in))
            elif call_name == "set":
                replacement = node.deep_replace(
                    node, cst.SetComp(elt=exp.elt, for_in=exp.for_in))
            elif call_name == "dict":
                elt = exp.elt
                key = None
                value = None
                if m.matches(elt, m.Tuple(m.DoNotCare(), m.DoNotCare())):
                    elt = cst.ensure_type(elt, cst.Tuple)
                    key = elt.elements[0].value
                    value = elt.elements[1].value
                elif m.matches(elt, m.List(m.DoNotCare(), m.DoNotCare())):
                    elt = cst.ensure_type(elt, cst.List)
                    key = elt.elements[0].value
                    value = elt.elements[1].value
                else:
                    # Unrecoginized form
                    return

                replacement = node.deep_replace(
                    node,
                    # pyre-fixme[6]: Expected `BaseAssignTargetExpression` for 1st
                    #  param but got `BaseExpression`.
                    cst.DictComp(key=key, value=value, for_in=exp.for_in),
                )

            self.report(node,
                        message_formatter.format(func=call_name),
                        replacement=replacement)
Ejemplo n.º 14
0
 def test_extract_optional_wildcard(self) -> None:
     expression = cst.parse_expression("a + b[c], d(e, f * g)")
     nodes = m.extract(
         expression,
         m.Tuple(elements=[
             m.DoNotCare(),
             m.Element(
                 m.Call(args=[
                     m.ZeroOrMore(),
                     m.ZeroOrOne(
                         m.Arg(m.SaveMatchedNode(m.Attribute(), "arg"))),
                 ])),
         ]),
     )
     self.assertEqual(nodes, {})
Ejemplo n.º 15
0
 def leave_Return(
     self, original_node: Return, updated_node: Return
 ) -> Union[BaseSmallStatement, RemovalSentinel]:
     if self.visiting_permalink_method and m.matches(updated_node.value, m.Tuple()):
         elem_0 = updated_node.value.elements[0]
         elem_1_3 = updated_node.value.elements[1:3]
         args = (
             Arg(elem_0.value),
             Arg(Name("None")),
             *[Arg(el.value) for el in elem_1_3],
         )
         return updated_node.with_changes(
             value=Call(func=Name("reverse"), args=args)
         )
     return super().leave_Return(original_node, updated_node)
Ejemplo n.º 16
0
 def test_extract_precedence_sequence_wildcard(self) -> None:
     expression = cst.parse_expression("a + b[c], d(e, f * g)")
     nodes = m.extract(
         expression,
         m.Tuple(elements=[
             m.DoNotCare(),
             m.Element(
                 m.Call(args=[
                     m.ZeroOrMore(
                         m.Arg(m.SaveMatchedNode(m.DoNotCare(), "arg")))
                 ])),
         ]),
     )
     extracted_node = (cst.ensure_type(
         cst.ensure_type(expression, cst.Tuple).elements[1].value,
         cst.Call).args[1].value)
     self.assertEqual(nodes, {"arg": extracted_node})
Ejemplo n.º 17
0
 def test_extract_optional_wildcard_present(self) -> None:
     expression = cst.parse_expression("a + b[c], d(e, f * g, h.i.j)")
     nodes = m.extract(
         expression,
         m.Tuple(elements=[
             m.DoNotCare(),
             m.Element(
                 m.Call(args=[
                     m.DoNotCare(),
                     m.DoNotCare(),
                     m.ZeroOrOne(
                         m.Arg(m.SaveMatchedNode(m.Attribute(), "arg"))),
                 ])),
         ]),
     )
     extracted_node = (cst.ensure_type(
         cst.ensure_type(expression, cst.Tuple).elements[1].value,
         cst.Call).args[2].value)
     self.assertEqual(nodes, {"arg": extracted_node})
Ejemplo n.º 18
0
 def test_extract_precedence_parent(self) -> None:
     expression = cst.parse_expression("a + b[c], d(e, f * g)")
     nodes = m.extract(
         expression,
         m.Tuple(elements=[
             m.DoNotCare(),
             m.Element(
                 m.SaveMatchedNode(
                     m.Call(args=[
                         m.Arg(m.SaveMatchedNode(m.Name(), "name")),
                         m.DoNotCare(),
                     ]),
                     "name",
                 )),
         ]),
     )
     extracted_node = cst.ensure_type(expression,
                                      cst.Tuple).elements[1].value
     self.assertEqual(nodes, {"name": extracted_node})
Ejemplo n.º 19
0
 def test_extract_sequence_multiple_wildcards(self) -> None:
     expression = cst.parse_expression("1, 2, 3, 4")
     nodes = m.extract(
         expression,
         m.Tuple(elements=(
             m.SaveMatchedNode(m.ZeroOrMore(), "head"),
             m.SaveMatchedNode(m.Element(value=m.Integer(
                 value="3")), "element"),
             m.SaveMatchedNode(m.ZeroOrMore(), "tail"),
         )),
     )
     tuple_elements = cst.ensure_type(expression, cst.Tuple).elements
     self.assertEqual(
         nodes,
         {
             "head": tuple(tuple_elements[:2]),
             "element": tuple_elements[2],
             "tail": tuple(tuple_elements[3:]),
         },
     )
Ejemplo n.º 20
0
class RemoveParenthesesFromReturn(NoqaAwareTransformer):
    @m.leave(
        m.Return(value=m.Tuple(lpar=m.MatchIfTrue(lambda v: v is not None))))
    def remove_parentheses_from_return(self, original_node: cst.Return,
                                       updated_node: cst.Return) -> cst.Return:

        # We get position of the `original_node`, since `updated_node` is
        # by definition different and was not processed by metadata provider.
        position: cst.metadata.CodeRange = self.get_metadata(
            PositionProvider, original_node)

        # Removing parentheses which are used to enable multi-line expression
        # will lead to invalid code, so we do nothing.
        if position.start.line != position.end.line:
            return original_node

        return updated_node.with_deep_changes(cst.ensure_type(
            updated_node.value, cst.Tuple),
                                              lpar=[],
                                              rpar=[])
Ejemplo n.º 21
0
    def __extract_variable_name(self, node: cst.AssignTarget):
        extracted_var_names = match.extract(
            node,
            match.AssignTarget(  # Assignment operator
                target=match.OneOf(  # Two cases exist
                    match.Name(  # Single target
                        value=match.SaveMatchedNode(  # Save result
                            match.MatchRegex(
                                r'(.)+'),  # Match any string literal
                            "name")),
                    match.Tuple(  # Multi-target
                        elements=match.SaveMatchedNode(  # Save result
                            match.DoNotCare(),  # Type of list
                            "names")),
                    # This extracts variables inside __init__ without type annotation (e.g. self.x=2)
                    match.Attribute(
                        value=match.Name(value=match.SaveMatchedNode(
                            match.MatchRegex(r'(.)+'),
                            "obj_name"  # Object name
                        )),
                        attr=match.Name(
                            match.SaveMatchedNode(match.MatchRegex(r'(.)+'),
                                                  "name")),
                    ))))

        if extracted_var_names is not None:
            if "name" in extracted_var_names:
                t = self.__get_type_from_metadata(node.target)
                extracted_var_names['type'] = (t, INF_TYPE_ANNOT
                                               if t else UNK_TYPE_ANNOT)
                return extracted_var_names
            elif "names" in extracted_var_names:
                return {
                    'names':
                    self.__extract_names_multi_assign(
                        list(extracted_var_names['names']))
                }
        else:
            return extracted_var_names
Ejemplo n.º 22
0
class RemoveParenthesesFromReturn(cst.CSTTransformer):
    @m.call_if_inside(m.Return(value=m.Tuple()))
    @m.leave(m.DoesNotMatch(m.Tuple(lpar=[])))
    def leave_Tuple(self, original_node: "Tuple",
                    updated_node: "Tuple") -> "Tuple":
        return original_node.with_changes(lpar=[], rpar=[])
    def visit_Call(self, node: cst.Call) -> None:
        result = m.extract(
            node,
            m.Call(
                func=m.Attribute(value=m.Name("self"),
                                 attr=m.Name("assertTrue")),
                args=[
                    m.DoNotCare(),
                    m.Arg(value=m.SaveMatchedNode(
                        m.OneOf(
                            m.Integer(),
                            m.Float(),
                            m.Imaginary(),
                            m.Tuple(),
                            m.List(),
                            m.Set(),
                            m.Dict(),
                            m.Name("None"),
                            m.Name("True"),
                            m.Name("False"),
                        ),
                        "second",
                    )),
                ],
            ),
        )

        if result:
            second_arg = result["second"]
            if isinstance(second_arg, Sequence):
                second_arg = second_arg[0]

            if m.matches(second_arg, m.Name("True")):
                new_call = node.with_changes(args=[
                    node.args[0].with_changes(comma=cst.MaybeSentinel.DEFAULT)
                ], )
            elif m.matches(second_arg, m.Name("None")):
                new_call = node.with_changes(
                    func=node.func.with_deep_changes(
                        old_node=cst.ensure_type(node.func,
                                                 cst.Attribute).attr,
                        value="assertIsNone",
                    ),
                    args=[
                        node.args[0].with_changes(
                            comma=cst.MaybeSentinel.DEFAULT)
                    ],
                )
            elif m.matches(second_arg, m.Name("False")):
                new_call = node.with_changes(
                    func=node.func.with_deep_changes(
                        old_node=cst.ensure_type(node.func,
                                                 cst.Attribute).attr,
                        value="assertFalse",
                    ),
                    args=[
                        node.args[0].with_changes(
                            comma=cst.MaybeSentinel.DEFAULT)
                    ],
                )
            else:
                new_call = node.with_deep_changes(
                    old_node=cst.ensure_type(node.func, cst.Attribute).attr,
                    value="assertEqual",
                )

            self.report(node, replacement=new_call)
Ejemplo n.º 24
0
    def visit_Call(self, node: cst.Call) -> None:
        if m.matches(
                node,
                m.Call(
                    func=m.Name("tuple") | m.Name("list") | m.Name("set")
                    | m.Name("dict"),
                    args=[m.Arg(value=m.List() | m.Tuple())],
                ),
        ) or m.matches(
                node,
                m.Call(func=m.Name("tuple") | m.Name("list") | m.Name("dict"),
                       args=[]),
        ):

            pairs_matcher = m.ZeroOrMore(
                m.Element(m.Tuple(
                    elements=[m.DoNotCare(), m.DoNotCare()]))
                | m.Element(m.List(
                    elements=[m.DoNotCare(), m.DoNotCare()])))

            exp = cst.ensure_type(node, cst.Call)
            call_name = cst.ensure_type(exp.func, cst.Name).value

            # If this is a empty call, it's an Unnecessary Call where we rewrite the call
            # to literal, except set().
            if not exp.args:
                elements = []
                message_formatter = UNNCESSARY_CALL
            else:
                arg = exp.args[0].value
                elements = cst.ensure_type(
                    arg, cst.List
                    if isinstance(arg, cst.List) else cst.Tuple).elements
                message_formatter = UNNECESSARY_LITERAL

            if call_name == "tuple":
                new_node = cst.Tuple(elements=elements)
            elif call_name == "list":
                new_node = cst.List(elements=elements)
            elif call_name == "set":
                # set() doesn't have an equivelant literal call. If it was
                # matched here, it's an unnecessary literal suggestion.
                if len(elements) == 0:
                    self.report(
                        node,
                        UNNECESSARY_LITERAL.format(func=call_name),
                        replacement=node.deep_replace(
                            node, cst.Call(func=cst.Name("set"))),
                    )
                    return
                new_node = cst.Set(elements=elements)
            elif len(elements) == 0 or m.matches(
                    exp.args[0].value,
                    m.Tuple(elements=[pairs_matcher])
                    | m.List(elements=[pairs_matcher]),
            ):
                new_node = cst.Dict(elements=[(
                    lambda val: cst.DictElement(val.elements[
                        0].value, val.elements[1].value))(cst.ensure_type(
                            ele.value,
                            cst.Tuple if isinstance(ele.value, cst.Tuple
                                                    ) else cst.List,
                        )) for ele in elements])
            else:
                # Unrecoginized form
                return

            self.report(
                node,
                message_formatter.format(func=call_name),
                replacement=node.deep_replace(node, new_node),
            )
Ejemplo n.º 25
0
    def obf_universal(self, node: cst.CSTNode, *types):

        if m.matches(node, m.Name()):
            types = ('a', 'ca', 'v', 'cv') if not types else types
            node = cst.ensure_type(node, cst.Name)
            if self.can_rename(node.value, *types):
                node = self.get_new_cst_name(node)

        elif m.matches(node, m.NameItem()):
            node = cst.ensure_type(node, cst.NameItem)
            node = node.with_changes(name=self.obf_universal(node.name))

        elif m.matches(node, m.Call()):

            node = cst.ensure_type(node, cst.Call)
            if self.change_methods or self.change_functions:
                node = self.new_obf_function_name(node)
            if self.change_arguments or self.change_method_arguments:
                node = self.obf_function_args(node)

        elif m.matches(node, m.Attribute()):
            node = cst.ensure_type(node, cst.Attribute)
            value = node.value
            attr = node.attr

            self.obf_universal(value)
            self.obf_universal(attr)

        elif m.matches(node, m.AssignTarget()):
            node = cst.ensure_type(node, cst.AssignTarget)
            node = node.with_changes(target=self.obf_universal(node.target))

        elif m.matches(node, m.List() | m.Tuple()):
            node = cst.ensure_type(node, cst.List) if m.matches(
                node, m.List()) else cst.ensure_type(node, cst.Tuple)
            new_elements = []
            for el in node.elements:
                new_elements.append(self.obf_universal(el))
            node = node.with_changes(elements=new_elements)
        elif m.matches(node, m.Subscript()):
            node = cst.ensure_type(node, cst.Subscript)
            new_slice = []
            for el in node.slice:
                new_slice.append(
                    el.with_changes(slice=self.obf_slice(el.slice)))
            node = node.with_changes(slice=new_slice)
            node = node.with_changes(value=self.obf_universal(node.value))
        elif m.matches(node, m.Element()):
            node = cst.ensure_type(node, cst.Element)
            node = node.with_changes(value=self.obf_universal(node.value))

        elif m.matches(node, m.Dict()):
            node = cst.ensure_type(node, cst.Dict)
            new_elements = []
            for el in node.elements:
                new_elements.append(self.obf_universal(el))
            node = node.with_changes(elements=new_elements)
        elif m.matches(node, m.DictElement()):
            node = cst.ensure_type(node, cst.DictElement)
            new_key = self.obf_universal(node.key)
            new_val = self.obf_universal(node.value)
            node = node.with_changes(key=new_key, value=new_val)
        elif m.matches(node, m.StarredDictElement()):
            node = cst.ensure_type(node, cst.StarredDictElement)
            node = node.with_changes(value=self.obf_universal(node.value))

        elif m.matches(node, m.If() | m.While()):
            node = cst.ensure_type(node, cst.IfExp) if m.matches(
                node, cst.If
                | cst.IfExp) else cst.ensure_type(node, cst.While)
            node = node.with_changes(test=self.obf_universal(node.test))
        elif m.matches(node, m.IfExp()):
            node = cst.ensure_type(node, cst.IfExp)
            node = node.with_changes(body=self.obf_universal(node.body))
            node = node.with_changes(test=self.obf_universal(node.test))
            node = node.with_changes(orelse=self.obf_universal(node.orelse))

        elif m.matches(node, m.Comparison()):
            node = cst.ensure_type(node, cst.Comparison)
            new_compars = []
            for target in node.comparisons:
                new_compars.append(self.obf_universal(target))

            node = node.with_changes(left=self.obf_universal(node.left))
            node = node.with_changes(comparisons=new_compars)
        elif m.matches(node, m.ComparisonTarget()):
            node = cst.ensure_type(node, cst.ComparisonTarget)
            node = node.with_changes(
                comparator=self.obf_universal(node.comparator))

        elif m.matches(node, m.FormattedString()):
            node = cst.ensure_type(node, cst.FormattedString)
            new_parts = []
            for part in node.parts:
                new_parts.append(self.obf_universal(part))
            node = node.with_changes(parts=new_parts)
        elif m.matches(node, m.FormattedStringExpression()):
            node = cst.ensure_type(node, cst.FormattedStringExpression)
            node = node.with_changes(
                expression=self.obf_universal(node.expression))

        elif m.matches(node, m.BinaryOperation() | m.BooleanOperation()):
            node = cst.ensure_type(node, cst.BinaryOperation) if m.matches(
                node, m.BinaryOperation()) else cst.ensure_type(
                    node, cst.BooleanOperation)
            node = node.with_changes(left=self.obf_universal(node.left),
                                     right=self.obf_universal(node.right))
        elif m.matches(node, m.UnaryOperation()):
            node = cst.ensure_type(node, cst.UnaryOperation)
            node = node.with_changes(
                expression=self.obf_universal(node.expression))

        elif m.matches(node, m.ListComp()):
            node = cst.ensure_type(node, cst.ListComp)
            node = node.with_changes(elt=self.obf_universal(node.elt))
            node = node.with_changes(for_in=self.obf_universal(node.for_in))

        elif m.matches(node, m.DictComp()):
            node = cst.ensure_type(node, cst.DictComp)
            node = node.with_changes(key=self.obf_universal(node.key))
            node = node.with_changes(value=self.obf_universal(node.value))
            node = node.with_changes(for_in=self.obf_universal(node.for_in))

        elif m.matches(node, m.CompFor()):
            node = cst.ensure_type(node, cst.CompFor)
            new_ifs = []

            node = node.with_changes(target=self.obf_universal(node.target))
            node = node.with_changes(iter=self.obf_universal(node.iter))
            for el in node.ifs:
                new_ifs.append(self.obf_universal(el))
            node = node.with_changes(ifs=new_ifs)
        elif m.matches(node, m.CompIf()):
            node = cst.ensure_type(node, cst.CompIf)
            node = node.with_changes(test=self.obf_universal(node.test))

        elif m.matches(node, m.Integer() | m.Float() | m.SimpleString()):
            pass

        else:
            pass
            # print(node)

        return node