Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating a list of all possible function paths #1

Closed
Gharibw opened this issue May 9, 2018 · 3 comments
Closed

Creating a list of all possible function paths #1

Gharibw opened this issue May 9, 2018 · 3 comments
Labels

Comments

@Gharibw
Copy link

Gharibw commented May 9, 2018

Pyan has been super helpful to me! However, I would like to use it in a different way to output, in addition to the current graphs, a list of all possible functions' paths start->end.
Right now, the Graph edges include the source and the target (e.g., A -> B and another edge B -> C). What I want to do is to print (A -> B -> C).
Is that currently supported? If not, where to start? Any guidance is appreciated.

#Assume we have the following functions:
def A(): 
    C()
    B()
def B():
    C()

I want the output to be something like:
A -> C -> D
A -> B -> C -> D

@Technologicat
Copy link
Owner

Unfortunately, that's not supported. But you could extract that information by walking the graph in a variety of ways:

  1. Read in Pyan's output file in a completely separate program, or

  2. Use Pyan's analyzer as a library, and grab the information directly from its data structures once it's done running.

For option 2, specifically, look at uses_edges in analyzer.py; it's a dictionary, where the key is a Node object (node.py), and the corresponding value is a list of Node objects. The key is the "from", the items in the value list are the "to"s.

So given a CallGraphVisitor instance analyzer, it should be possible to do something like:

def make_chains(edges):
    def make_chains_rec(from_node):
        to_nodes = edges.get(from_node, [])
        if len(to_nodes):
            chains = []
            for target in to_nodes:
                tails = make_chains_rec(target)
                for tail in tails:
                    chains.append([from_node] + tail)
            return chains
        else:
            return [from_node]

    all_chains = {}
    for from_node in edges.keys():
        all_chains[from_node] = analyzerec(from_node)

    return all_chains

make_chains(analyzer.uses_edges)

...modulo any bugs. This is a fairly simple recursive problem, but I didn't actually test the solution ;)

There's also a defines_edges, which has the same format, if you want to do this analysis for "defines" relationships. (Maybe useful to catch nested defs, otherwise maybe not so interesting.)

As for how to instantiate and run the CallGraphVisitor, look at main.py.

Hope this helps!

@Technologicat
Copy link
Owner

One more thing - once you have the output of make_chains, you may be interested in the flavor, name and namespace attributes of the Node objects.

(And there's at least one typo in the above code snippet - analyzerec should be make_chains_rec. Renamed it for clarity, but forgot to change one of the calls.)

@Technologicat
Copy link
Owner

No new comments since end of May, closing issue. Feel free to re-open if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants