1 19 20 package org.netbeans.api.java.source.query; 21 22 import org.netbeans.modules.java.source.engine.EngineEnvironment; 23 import javax.lang.model.element.Element; 24 import javax.lang.model.element.TypeElement; 25 import org.netbeans.modules.java.source.engine.ASTModel; 26 import org.netbeans.modules.java.source.engine.EngineEnvironment; 27 28 import com.sun.source.tree.*; 29 import com.sun.source.util.TreeScanner; 30 31 import java.util.BitSet ; 32 import java.util.HashMap ; 33 import java.util.HashSet ; 34 import java.util.Map ; 35 import java.util.Stack ; 36 37 42 public class CallGraph { 43 44 private Element rootMethod; 45 private Node[] nodes; 46 private int nnodes; 47 private ASTModel model; 48 49 public CallGraph(Element method, QueryEnvironment env) { 50 this.model = ((EngineEnvironment)env).getModel(); 51 nodes = new Node[1]; 52 rootMethod = method; 53 } 54 55 public Node find(Element method) { 56 int inode = findNode(method); 57 return (inode != -1) ? nodes[inode] : null; 58 } 59 60 public Node[] getNodes() { 61 Node[] newa = new Node[nnodes]; 62 System.arraycopy(nodes, 0, newa, 0, nnodes); 63 return newa; 64 } 65 66 private int findNode(Element method) { 67 for (int i = 0; i < nnodes; i++) { 68 if (method.equals(nodes[i].sym)) 69 return i; 70 } 71 return -1; 72 } 73 74 public Node[] getPath(Element method) { 75 int meth = findNode(method); 76 if (meth == -1) 77 return new Node[0]; 78 Stack stack = new Stack (); 79 BitSet visited = new BitSet (nnodes); 80 getPath(0, meth, stack, visited); 81 Node[] ret = new Node[stack.size()]; 82 stack.toArray(ret); 83 return ret; 84 } 85 86 public String getPathString(Element method) { 87 Node[] nodes = getPath(method); 88 if (nodes.length == 0) 89 return "<no path>"; 90 StringBuffer sb = new StringBuffer (); 91 Element clazz = method.getEnclosingElement(); 92 for (int i = 0; i < nodes.length; i++) { 93 Element m = nodes[i].sym; 94 Element ec = m.getEnclosingElement(); 95 if (!ec.equals(clazz)) { 96 sb.append(ec.getSimpleName()); 97 sb.append('.'); 98 } 99 sb.append(m.getSimpleName()); 100 if (i < nodes.length-1) 101 sb.append("->"); 102 } 103 return sb.toString(); 104 } 105 106 private static String makeNodeName(Element meth, TypeElement clazz) { 107 StringBuffer sb = new StringBuffer (); 108 TypeElement encClz = (TypeElement)meth.getEnclosingElement(); 109 if (!encClz.equals(clazz)) { 110 sb.append(encClz.getQualifiedName()); 111 sb.append('.'); 112 } 113 sb.append(meth.getSimpleName()); 114 return sb.toString(); 115 } 116 117 121 private boolean getPath(int from, int to, Stack path, BitSet visited) { 122 Node n = nodes[from]; 123 path.push(n); 124 visited.set(from); 125 if (from == to) 126 return false; 127 else 128 for (int i = 0; i < n.ncalls; i++) { 129 int inode = n.calls[i]; 130 if (!visited.get(inode)) 131 if (!getPath(inode, to, path, visited)) 132 return false; 133 } 134 path.pop(); 135 return true; 136 } 137 138 142 private int addNode(Element method) { 143 int inode = findNode(method); 144 if (inode == -1) { 145 if (nnodes == nodes.length) { 146 Node[] newa = new Node[nnodes * 2 + 1]; 147 System.arraycopy(nodes, 0, newa, 0, nnodes); 148 nodes = newa; 149 } 150 inode = nnodes++; 151 nodes[inode] = new Node(method); 152 } 153 return inode; 154 } 155 156 public void buildGraph() { 157 symbols = new HashMap <Element, Tree>(); addTrees(symbols, model.getRoot()); 159 scanCalls(rootMethod, null); 160 symbols = null; } 162 163 private void addTrees(Map <Element, Tree> map, Tree t) { 164 Element sym = model.getElement(t); 165 if (sym != null) { 166 map.put(sym, t); 167 for (Tree child : model.getChildren(t)) 168 addTrees(map, child); 169 } 170 } 171 172 private Map <Element, Tree> symbols; 173 174 private void scanCalls(Element method, Node callingNode) { 175 int inode = findNode(method); 176 boolean needsScan = inode == -1; 177 if (needsScan) 178 inode = addNode(method); 179 180 if (callingNode != null) 181 callingNode.addCall(inode); 182 183 if (!needsScan) 184 return; 185 186 final Node node = nodes[inode]; 187 188 Tree tree = symbols.get(method); 189 if (tree == null) 190 return; 191 tree.accept(new TreeScanner<Void ,Object >() { 192 @Override 193 public Void visitMethodInvocation(MethodInvocationTree t, Object p) { 194 Element meth = model.getElement(t.getMethodSelect()); 195 if (meth != null && acceptCall(meth, t)) 196 scanCalls(meth, node); 197 super.visitMethodInvocation(t, p); 198 return null; 199 } 200 @Override 201 public Void visitNewClass(NewClassTree t, Object p) { 202 Element constructor = model.getElement(t); 203 if (acceptCall(constructor, t)) 204 scanCalls(constructor, node); 205 super.visitNewClass(t, p); 206 return null; 207 } 208 }, null); 209 } 210 211 220 public boolean acceptCall(Element symbol, Tree tree) { 221 return true; 222 } 223 224 public void list() { 225 list(find(rootMethod), 0, new HashSet ()); 226 } 227 228 private void list(Node node, int indent, HashSet listed) { 229 for (int i = 0 ; i < indent ; i++) { 230 System.out.print(" "); 231 } 232 if (listed.contains(node)) 233 System.out.println("<" + node.getElement() + ">"); 234 else { 235 listed.add(node); 236 System.out.println(node.getElement()); 237 Node[] calls = node.getCalls(this); 238 for (int i = 0; i < calls.length; i++) 239 list(calls[i], indent + 1, listed); 240 } 241 } 242 243 246 public static class Node { 247 Element sym; int[] calls = new int[0]; int ncalls = 0; 250 251 Node(Element sym) { 252 this.sym = sym; 253 } 254 255 public Element getElement() { 256 return sym; 257 } 258 259 Node[] getCalls(CallGraph cg) { 260 Node[] newa = new Node[ncalls]; 261 for (int i = 0; i < ncalls; i++) 262 newa[i] = cg.nodes[calls[i]]; 263 return newa; 264 } 265 266 void addCall(int inode) { 267 assert ncalls <= calls.length; 268 if (ncalls == calls.length) { 269 int[] newa = new int[ncalls * 2 + 1]; 270 System.arraycopy(calls, 0, newa, 0, ncalls); 271 calls = newa; 272 } 273 calls[ncalls++] = inode; 274 } 275 276 public String toString() { 277 return sym.getSimpleName().toString(); 278 } 279 } 280 } 281 | Popular Tags |