Created
April 7, 2013 19:55
-
-
Save pxpc2/5332228 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package us.brtm.cfg.generic; | |
import org.objectweb.asm.tree.analysis.*; | |
import java.util.HashSet; | |
import java.util.Set; | |
/** | |
* @author Pedro Daia Cardoso | |
*/ | |
public class Node<V extends Value> extends Frame<V> { | |
private Set<Node<V>> successors = new HashSet<>(); | |
public Node(Frame<? extends V> src) { | |
super(src); | |
} | |
public Node(int nLocals, int nStack) { | |
super(nLocals, nStack); | |
} | |
public Set<Node<V>> getSuccessors() { | |
return successors; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package us.brtm.cfg; | |
import org.objectweb.asm.tree.AbstractInsnNode; | |
import org.objectweb.asm.tree.LabelNode; | |
import org.objectweb.asm.tree.MethodNode; | |
import org.objectweb.asm.tree.analysis.*; | |
import us.brtm.cfg.generic.Node; | |
/** | |
* @author Pedro Daia Cardoso | |
*/ | |
public class Graph { | |
/** | |
* The representation of the analyzed method. | |
*/ | |
private MethodNode method; | |
/** | |
* The analyzer instance of an analyzed method :P | |
*/ | |
private Analyzer<BasicValue> analyzer; | |
/** | |
* @param owner the internal name of the class to which the method belongs. | |
* @param method the method to be analyzed. | |
* @throws AnalyzerException if a problem occurs during the analysis. | |
*/ | |
public Graph(String owner, MethodNode method) throws AnalyzerException { | |
this.method = method; | |
this.analyzer = new Analyzer<BasicValue>(new BasicInterpreter()) { | |
protected Frame<BasicValue> newFrame(int nLocals, int nStack) { | |
return new Node<>(nLocals, nStack); | |
} | |
protected Frame<BasicValue> newFrame(Frame<? extends BasicValue> src) { | |
return new Node<>(src); | |
} | |
protected void newControlFlowEdge(int src, int dst) { | |
Node<BasicValue> s = (Node<BasicValue>) getFrames()[src]; | |
s.getSuccessors().add((Node<BasicValue>) getFrames()[dst]); | |
} | |
}; | |
this.analyzer.analyze(owner, method); | |
} | |
/** | |
* Optimizes the method by removing useless things and/or | |
* simplifying the code. | |
*/ | |
public void optimizeMethod() { | |
Frame<BasicValue>[] frames = analyzer.getFrames(); | |
AbstractInsnNode[] instructions = method.instructions.toArray(); | |
for (int i = 0; i < frames.length; i++) { | |
AbstractInsnNode instruction = instructions[i]; | |
if (frames[i] == null && !(instruction instanceof LabelNode)) { | |
method.instructions.remove(instructions[i]); | |
} | |
} | |
} | |
/** | |
* A simple method to calculate the cyclomatic | |
* complexity of a method. This metric is defined | |
* as the number of edges in the control flow graph, | |
* minus the number of nodes, plus two. | |
* The metric gives a good indication if the complexity | |
* of a method, which have a relation with the average | |
* amount of bugs in the method. | |
* | |
* @return the cyclomatic complexity of this graph's method. | |
*/ | |
public int getCyclomaticComplexity() { | |
Frame<BasicValue>[] frames = analyzer.getFrames(); | |
int edges = 0; | |
int nodes = 0; | |
for (Frame<BasicValue> frame : frames) { | |
if (frame != null) { | |
edges += ((Node<BasicValue>) frame).getSuccessors().size(); | |
nodes += 1; | |
} | |
} | |
return edges - nodes + 2; | |
} | |
/** | |
* @return returns the analyzer instance | |
*/ | |
public Analyzer getAnalyzer() { | |
return analyzer; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment