001: package soot.toolkits.astmetrics;
002:
003: import java.util.*;
004:
005: import polyglot.ast.*;
006: import polyglot.util.CodeWriter;
007: import polyglot.visit.NodeVisitor;
008:
009: public class StmtSumWeightedByDepth extends ASTMetric {
010:
011: int currentDepth;
012: int sum;
013: int maxDepth;
014: int numNodes;
015:
016: Stack<ArrayList> labelNodesSoFar = new Stack<ArrayList>();
017: ArrayList<Node> blocksWithAbruptFlow = new ArrayList<Node>();
018: HashMap<Node, Integer> stmtToMetric = new HashMap<Node, Integer>();
019: HashMap<Node, Integer> stmtToMetricDepth = new HashMap<Node, Integer>();
020:
021: public static boolean tmpAbruptChecker = false;
022:
023: public StmtSumWeightedByDepth(Node node) {
024: super (node);
025: }
026:
027: public void printAstMetric(Node n, CodeWriter w) {
028: if (n instanceof Stmt) {
029: if (stmtToMetric.containsKey(n)) {
030: w.write(" // sum= " + stmtToMetric.get(n)
031: + " : depth= " + stmtToMetricDepth.get(n)
032: + "\t");
033: }
034: }
035: }
036:
037: public void reset() {
038: // if not one, then fields and method sigs don't get counted
039: currentDepth = 1; //inside a class
040: maxDepth = 1;
041: sum = 0;
042: numNodes = 0;
043: }
044:
045: public void addMetrics(ClassData data) {
046: //data.addMetric(new MetricData("MaxDepth",new Integer(maxDepth)));
047:
048: data
049: .addMetric(new MetricData("D-W-Complexity", new Double(
050: sum)));
051:
052: data.addMetric(new MetricData("AST-Node-Count", new Integer(
053: numNodes)));
054: }
055:
056: private void increaseDepth() {
057: System.out.println("Increasing depth");
058: currentDepth++;
059: if (currentDepth > maxDepth)
060: maxDepth = currentDepth;
061: }
062:
063: private void decreaseDepth() {
064: System.out.println("Decreasing depth");
065: currentDepth--;
066: }
067:
068: /*
069: * List of Node types which increase depth of traversal!!!
070: * Any construct where one can have a { } increases the depth
071: * hence even though if(cond) stmt doesnt expicitly use a block
072: * its depth is still +1 when executing the stmt
073: *
074: * If the "if" stmt has code if(cond) { stmt } OR if(cond) stmt this will only increase the depth by 1 (ignores compound stmt blocks)
075: *
076: * If, Loop, Try, Synch, ProcDecl, Init, Switch, LocalClassDecl .... add currentDepth to sum and then increase depth by one
077: * irrespective of how many stmts there are in the body
078: *
079: * Block ... if it is a block within a block, add currentDepth plus increment depth ONLY if it has abrupt flow out of it.
080: */
081: public NodeVisitor enter(Node parent, Node n) {
082: numNodes++;
083: if (n instanceof CodeDecl) {
084: // maintain stack of label arrays (can't have label from inside method to outside)
085: labelNodesSoFar.push(new ArrayList());
086: } else if (n instanceof Labeled) {
087: // add any labels we find to the array
088: labelNodesSoFar.peek().add(((Labeled) n).label());
089: }
090:
091: if (n instanceof If || n instanceof Loop || n instanceof Try
092: || n instanceof Switch || n instanceof LocalClassDecl
093: || n instanceof Synchronized
094: || n instanceof ProcedureDecl
095: || n instanceof Initializer) {
096: sum += currentDepth * 2;
097: System.out.println(n);
098: increaseDepth();
099: } else if (parent instanceof Block && n instanceof Block) {
100: StmtSumWeightedByDepth.tmpAbruptChecker = false;
101: n.visit(new NodeVisitor() {
102: // extended NodeVisitor that checks for branching out of a block
103: public NodeVisitor enter(Node parent, Node node) {
104: if (node instanceof Branch) {
105: Branch b = (Branch) node;
106: // null branching out of a plain block is NOT ALLOWED!
107: if (b.label() != null
108: && labelNodesSoFar.peek().contains(
109: b.label())) {
110: StmtSumWeightedByDepth.tmpAbruptChecker = true;
111: }
112: }
113: return enter(node);
114: }
115:
116: // this method simply stops further node visiting if we found our info
117: public Node override(Node parent, Node node) {
118: if (StmtSumWeightedByDepth.tmpAbruptChecker)
119: return node;
120: return null;
121: }
122: });
123:
124: if (StmtSumWeightedByDepth.tmpAbruptChecker) {
125: blocksWithAbruptFlow.add(n);
126: sum += currentDepth * 2;
127: System.out.println(n);
128: increaseDepth();
129: }
130: }
131: // switch from Stmt to Expr here, since Expr is the smallest unit
132: else if (n instanceof Expr || n instanceof Formal) {
133: System.out.print(sum + " " + n + " ");
134: sum += currentDepth * 2;
135: System.out.println(sum);
136: }
137:
138: // carry metric cummulative for each statement for metricPrettyPrinter
139: if (n instanceof Stmt) {
140: stmtToMetric.put(n, new Integer(sum));
141: stmtToMetricDepth.put(n, new Integer(currentDepth));
142: }
143:
144: return enter(n);
145: }
146:
147: public Node leave(Node old, Node n, NodeVisitor v) {
148:
149: // stack maintenance, if leaving a method
150: if (n instanceof CodeDecl)
151: labelNodesSoFar.pop();
152:
153: if (n instanceof If || n instanceof Loop || n instanceof Try
154: || n instanceof Switch || n instanceof LocalClassDecl
155: || n instanceof Synchronized
156: || n instanceof ProcedureDecl
157: || n instanceof Initializer) {
158: decreaseDepth();
159: } else if (n instanceof Block
160: && blocksWithAbruptFlow.contains(n)) {
161: decreaseDepth();
162: }
163: return n;
164: }
165: }
|