Beispiel #1
0
class AddFunctionArgumentRule:
    """
    adds additional unused function arguments

    function foo(x) {
      ...
    }

    ->

    function foo(x, arg1, arg2) {
       ...
    }
    """
    def __init__(self):
        self.name = "AddFunctionArgument"
        self.applied_positions = {}
        self.analyzer = TypeScriptGraphAnalyzer()

        self.null_id = "<null>"

    def revert_all_changes(self):
        for original_node, swapped_node in self.applied_positions.values():
            swapped_node.swapNodes(original_node)
        self.applied_positions.clear()

    def matches(self, node: AstNode):
        return self.analyzer.is_function_def(node)

    def apply(self, tree_id, node: AstNode):
        assert self.matches(node)

        def find_params(function_def: AstNode):
            assert function_def.down_first() is not None
            c = function_def.down_first()
            while c.type != "OpenParenToken":
                c = c.right()
            assert c.has_right() and c.right().type == "SyntaxList"
            return c.right()

        params = find_params(node)
        new_params = params.deepCopy(parent=params.parent)
        for i in range(random.randint(1, 3)):
            param = AstNode(idx=-1, type="Parameter", value=self.null_id)
            # TODO: enable adversarial modifications of the added identifier
            ident = AstNode(idx=-1,
                            type="Identifier",
                            value="param{}".format(i))
            param.add_child(ident)

            if new_params.children:
                comma_token = AstNode(idx=-1, type="CommaToken", value=",")
                new_params.add_child(comma_token)
            new_params.add_child(param)

        assert params.id != -1
        key = (tree_id, params.id)
        assert key not in self.applied_positions
        "remember where the change was applied such that it can be reverted later"
        self.applied_positions[key] = (params, new_params)
        params.swapNodes(new_params)
Beispiel #2
0
class AddMethodCallArgumentsRule:
    """
    adds additional unused method call arguments

    console.log("hello world!")

    ->

    console.log("hello world!", expr1, expr2)

    where expr1, expr2 are randomly generated expressions.
    In JavaScript, additional arguments are ignored at runtime.
    Note however this change is not semantic preserving since the method could
    declare additional parameters in which case the generated expressions will be used.

    """
    def __init__(self, expr_gen: ExpressionGenerator):
        self.name = "AddMethodCallArguments"
        self.applied_positions = {}
        self.expr_gen = expr_gen

        self.null_id = "<null>"
        self.analyzer = TypeScriptGraphAnalyzer()

    def revert_all_changes(self):
        for original_node, swapped_node in self.applied_positions.values():
            swapped_node.swapNodes(original_node)
        self.applied_positions.clear()

    def matches(self, node: AstNode):
        return self.analyzer.is_function_def(node)

    """
===================    146       CallExpression	                    	                                     
====================   147 PropertyAccessExpr..	                    	                                     
=====================  148           Identifier	                 div	                 any            div  
=====================  149             DotToken	                   .	                                  .  
=====================  150           Identifier	             getText	                            getText  
====================   151       OpenParenToken	                   (	                                  (  
====================   152           SyntaxList	                    	                                     
====================   153      CloseParenToken	                   )	                                  )

===================    122       CallExpression	                    	                                     
====================   123 PropertyAccessExpr..	                    	                                     
=====================  124           Identifier	                  by	                 any          <unk>  
=====================  125             DotToken	                   .	                                  .  
=====================  126           Identifier	                 css	                                css  
====================   127       OpenParenToken	                   (	                                  (  
====================   128           SyntaxList	                    	                                     
=====================  129        StringLiteral	             'input'	              string        'input'  
====================   130      CloseParenToken	                   )	                                  )
    """

    def apply(self, tree_id, node: AstNode):
        assert self.matches(node)

        def find_args(function_def: AstNode):
            assert function_def.down_first() is not None
            c = function_def.down_first()
            while c.type != "OpenParenToken":
                c = c.right()
            assert c.has_right() and c.right().type == "SyntaxList"
            return c.right()

        args = find_args(node)
        new_args = args.deepCopy(parent=args.parent)
        for i in range(random.randint(1, 2)):
            if new_args.children:
                comma_token = AstNode(idx=-1, type="CommaToken", value=",")
                new_args.add_child(comma_token)
            expr = self.expr_gen.gen_bin_expr(depth=random.randint(0, 2))
            new_args.add_child(expr)

        assert args.id != -1
        key = (tree_id, args.id)
        assert key not in self.applied_positions
        "remember where the change was applied such that it can be reverted later"
        self.applied_positions[key] = (args, new_args)
        args.swapNodes(new_args)