Beispiel #1
0
 def _get_async_expr_replacement(
         self, node: cst.CSTNode) -> Optional[cst.CSTNode]:
     if m.matches(node, m.Call()):
         node = cast(cst.Call, node)
         return self._get_async_call_replacement(node)
     elif m.matches(node, m.Attribute()):
         node = cast(cst.Attribute, node)
         return self._get_async_attr_replacement(node)
     elif m.matches(node, m.UnaryOperation(operator=m.Not())):
         node = cast(cst.UnaryOperation, node)
         replacement_expression = self._get_async_expr_replacement(
             node.expression)
         if replacement_expression is not None:
             return node.with_changes(expression=replacement_expression)
     elif m.matches(node, m.BooleanOperation()):
         node = cast(cst.BooleanOperation, node)
         maybe_left = self._get_async_expr_replacement(node.left)
         maybe_right = self._get_async_expr_replacement(node.right)
         if maybe_left is not None or maybe_right is not None:
             left_replacement = maybe_left if maybe_left is not None else node.left
             right_replacement = (maybe_right if maybe_right is not None
                                  else node.right)
             return node.with_changes(left=left_replacement,
                                      right=right_replacement)
     return None
Beispiel #2
0
 def basic_parenthesize(
     node: libcst.CSTNode,
     whitespace: Optional[libcst.BaseParenthesizableWhitespace] = None,
 ) -> libcst.CSTNode:
     if not hasattr(node, "lpar"):
         return node
     if whitespace:
         return node.with_changes(
             lpar=[libcst.LeftParen(whitespace_after=whitespace)],
             rpar=[libcst.RightParen()],
         )
     return node.with_changes(lpar=[libcst.LeftParen()], rpar=[libcst.RightParen()])
Beispiel #3
0
 def _maybe_autofix_node(self, node: cst.CSTNode,
                         attribute_name: str) -> None:
     replacement_value = self._get_async_expr_replacement(
         getattr(node, attribute_name))
     if replacement_value is not None:
         replacement = node.with_changes(
             **{attribute_name: replacement_value})
         self.report(node, replacement=replacement)
Beispiel #4
0
 def _leave(self, original: cst.CSTNode, updated: cst.CSTNode) -> cst.CSTNode:
     # TODO: if global scope query create a module tree from scratch?
     # NOTE: in the future can cache lib cst node comparisons for speed
     match = notFound
     if first_ref_index is not None:
         match = tryFind(lambda m: original.deep_equals(
             m.path[first_ref_index].node), matches)
     if match is not notFound:
         from_assert = first(astNodeFromAssertion(transform, match))
         return from_assert
     elif original in transform.references:
         # TODO: replace references to anything destroyed by the transform
         pass
     elif find_attempt is notFound and isinstance(updated, cst.Module):
         module_match = Match(
             [CaptureExpr().contextualize(node=updated)])
         return updated.with_changes(body=(*updated.body, *astNodeFromAssertion(transform, module_match)))
     else:
         return updated
Beispiel #5
0
def render_node(node: cst.CSTNode, module: Optional[cst.Module] = None) -> str:
    if module is None:
        module = cst.Module(body=[])
    code = module.code_for_node(node.with_changes(leading_lines=()))
    return code
Beispiel #6
0
 def renamed(self, old_node: cst.CSTNode):
     return old_node.with_changes(name=self.get_new_cst_name(old_node.name))
Beispiel #7
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
Beispiel #8
0
    def _handle_suppression_comment(
        self,
        parent_node: cst.CSTNode,
        parent_attribute_name: str,
        index: int,
        local_supp_comment: SuppressionComment,
        comment_physical_line: int,
    ) -> None:
        ignored_rules = local_supp_comment.ignored_rules
        # Just a check for the type-checker - it should never actually be AllRulesType
        # because we don't support that in lint-fixme/lint-ignore comments.
        # TODO: We can remove the AllRulesType check once we deprecate noqa.
        if isinstance(ignored_rules, AllRulesType):
            return

        # First find the suppressed rules that were included in the lint run. If a rule was not included
        # in this run, we CANNOT know for sure that this lint suppression is unused.
        ignored_rules_that_ran = {ig for ig in ignored_rules if ig in self.rule_names}

        if not ignored_rules_that_ran:
            return

        lines_span = len(local_supp_comment.tokens)

        unneeded_codes = _get_unused_codes_in_comment(
            local_supp_comment, ignored_rules_that_ran
        )
        if unneeded_codes:
            new_comment_lines = _compose_new_comment(
                local_supp_comment, unneeded_codes, comment_physical_line
            )
            if not new_comment_lines:
                # If we're here, all of the codes in this suppression refer to rules that ran, and
                # none of comment's codes suppress anything, so we report this comment and offer to remove it.
                new_parent_attribute_value = _modify_parent_attribute(
                    parent_node, parent_attribute_name, index, index + lines_span, []
                )
                self.report(
                    parent_node,
                    message=UNUSED_SUPPRESSION_COMMENT_MESSAGE,
                    replacement=parent_node.with_changes(
                        **{parent_attribute_name: new_parent_attribute_value}
                    ),
                )
            else:
                node_to_replace = getattr(parent_node, parent_attribute_name)[index]
                replacement_emptyline_nodes = [
                    cst.EmptyLine(
                        indent=node_to_replace.indent,
                        whitespace=node_to_replace.whitespace,
                        comment=cst.Comment(line),
                    )
                    for line in new_comment_lines
                ]
                new_parent_attribute_value: List[
                    cst.EmptyLine
                ] = _modify_parent_attribute(
                    parent_node,
                    parent_attribute_name,
                    index,
                    index + lines_span,
                    replacement_emptyline_nodes,
                )

                self.report(
                    parent_node,
                    message=UNUSED_SUPPRESSION_CODES_IN_COMMENT_MESSAGE.format(
                        lint_codes="`, `".join(uc for uc in unneeded_codes)
                    ),
                    replacement=parent_node.with_changes(
                        **{parent_attribute_name: new_parent_attribute_value}
                    ),
                )