Exemplo n.º 1
0
    def loop_at(self, filename, lineno):

        if filename not in self.line_to_asts:
            self.line_to_asts[filename] = code_reader.make_line_to_asts(filename)
        for st in self.line_to_asts[filename][lineno]:
            if type(st) in (astroid.For, astroid.While):
                return st
        return None
Exemplo n.º 2
0
def analyze_flow(stmt_sequence, loop_stats):
    """
    Creates a data flow graph showing how information moves through the statement sequence.
    This should include an edge for every assignment (or impure function call) to where
    the variable is used.

    Conceptually there are two kinds of data flow:
    - Flow within an expression e.g. f(g(y)) ... y->g->f
    - Flow between statements (assign-use)

    The first often entails the other... e.g. g consists of statements.  So there are multiple
    conceptual levels.  For example in the above, the lowest level is the statements of g,
    which are "contained" in the expression g(y), which is contained in the expression f(g(y)).

    The flow of data in the above example is (def of y) -> (statements of g) -> (statements of f).
    This corresponds to the order statements are executed.

    In our graph we will want a node for each sub-expression of f(g(y)), and one for each sub-expression
    of each statement of f and g. In other words my nodes basically correspond to the "active" nodes of
    the AST, i.e. those that produce an intermediate value.

    loop_stats: a mapping from statement indices to LoopStats objects

    Function return: returns data to the node "containing" the function call

    """
    mainvar('last_stmt_sequence', stmt_sequence)

    stmt_sequence = [
        (os.path.abspath(f)[:-1] if f.endswith('pyc') else os.path.abspath(f),
         l, t) for (f, l, t) in stmt_sequence
    ]

    # Find all file names.  Yup, this is a set comprehension.
    filenames = {fn for (fn, _, __) in stmt_sequence}

    line_to_asts = {fn: code_reader.make_line_to_asts(fn) for fn in filenames}

    dfg = DataFlowGraph(stmt_sequence, line_to_asts, filenames, loop_stats)

    stmt, nstmts = follow_statements_until_return(dfg, 0, None, {})
    if isinstance(stmt, astroid.Return):
        last_node = sorted(dfg.terminal_nodes(),
                           key=lambda n: n.line.stmt_idx)[-1]
        dfg.add_terminal_edge(len(stmt_sequence) - 1, last_node)
    #terminal_nodes = dfg.terminal_nodes()
    #for tn in terminal_nodes:
    #if not tn.ast_node.is_statement:
    #dfg.add_terminal_edge(len(stmt_sequence)-1, tn)

    # For tracking where data from return statements will flow to (file/line)

    return dfg
Exemplo n.º 3
0
def analyze_flow(stmt_sequence, loop_stats):
    """
    Creates a data flow graph showing how information moves through the statement sequence.
    This should include an edge for every assignment (or impure function call) to where
    the variable is used.

    Conceptually there are two kinds of data flow:
    - Flow within an expression e.g. f(g(y)) ... y->g->f
    - Flow between statements (assign-use)

    The first often entails the other... e.g. g consists of statements.  So there are multiple
    conceptual levels.  For example in the above, the lowest level is the statements of g,
    which are "contained" in the expression g(y), which is contained in the expression f(g(y)).

    The flow of data in the above example is (def of y) -> (statements of g) -> (statements of f).
    This corresponds to the order statements are executed.

    In our graph we will want a node for each sub-expression of f(g(y)), and one for each sub-expression
    of each statement of f and g. In other words my nodes basically correspond to the "active" nodes of
    the AST, i.e. those that produce an intermediate value.

    loop_stats: a mapping from statement indices to LoopStats objects

    Function return: returns data to the node "containing" the function call

    """
    mainvar('last_stmt_sequence', stmt_sequence)

    stmt_sequence = [(os.path.abspath(f)[:-1] if f.endswith('pyc') else os.path.abspath(f), l, t)
            for (f,l,t) in stmt_sequence]

    # Find all file names.  Yup, this is a set comprehension.
    filenames = {fn for (fn,_,__) in stmt_sequence}

    line_to_asts = {fn: code_reader.make_line_to_asts(fn) for fn in filenames}

    dfg = DataFlowGraph(stmt_sequence, line_to_asts, filenames, loop_stats)

    stmt, nstmts = follow_statements_until_return(dfg, 0, None, {})
    if isinstance(stmt, astroid.Return):
        last_node = sorted(dfg.terminal_nodes(), key=lambda n: n.line.stmt_idx)[-1]
        dfg.add_terminal_edge(len(stmt_sequence)-1, last_node)
    #terminal_nodes = dfg.terminal_nodes()
    #for tn in terminal_nodes:
        #if not tn.ast_node.is_statement:
            #dfg.add_terminal_edge(len(stmt_sequence)-1, tn)

    # For tracking where data from return statements will flow to (file/line)


    return dfg