1 /* |
|
2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 |
|
25 package com.sun.classanalyzer; |
|
26 |
|
27 import java.io.File; |
|
28 import java.util.ArrayList; |
|
29 import java.util.HashMap; |
|
30 import java.util.List; |
|
31 import java.util.Map; |
|
32 import java.util.Set; |
|
33 import java.util.SortedMap; |
|
34 import java.util.TreeMap; |
|
35 import java.util.TreeSet; |
|
36 |
|
37 import com.sun.tools.classfile.AccessFlags; |
|
38 |
|
39 /** |
|
40 * |
|
41 * @author Mandy Chung |
|
42 */ |
|
43 public class Klass implements Comparable<Klass> { |
|
44 private final String classname; |
|
45 private final String packagename; |
|
46 private Module module; |
|
47 private boolean isJavaLangObject; |
|
48 private String[] paths; |
|
49 private Map<String, Set<Method>> methods; |
|
50 private AccessFlags accessFlags; |
|
51 private long filesize; |
|
52 |
|
53 private SortedMap<Klass, Set<ResolutionInfo>> deps; |
|
54 private SortedMap<Klass, Set<ResolutionInfo>> referrers; |
|
55 private List<AnnotatedDependency> annotatedDeps; |
|
56 private Set<String> classForNameRefs; |
|
57 |
|
58 private Klass(String classname) { |
|
59 this.classname = classname; |
|
60 this.paths = classname.replace('.', '/').split("/"); |
|
61 this.isJavaLangObject = classname.equals("java.lang.Object"); |
|
62 this.deps = new TreeMap<Klass, Set<ResolutionInfo>>(); |
|
63 this.referrers = new TreeMap<Klass, Set<ResolutionInfo>>(); |
|
64 this.methods = new HashMap<String, Set<Method>>(); |
|
65 this.annotatedDeps = new ArrayList<AnnotatedDependency>(); |
|
66 this.classForNameRefs = new TreeSet<String>(); |
|
67 |
|
68 int pos = classname.lastIndexOf('.'); |
|
69 this.packagename = (pos > 0) ? classname.substring(0, pos) : "<unnamed>"; |
|
70 } |
|
71 |
|
72 String getBasename() { |
|
73 return paths[paths.length - 1]; |
|
74 } |
|
75 |
|
76 String getClassName() { |
|
77 return classname; |
|
78 } |
|
79 |
|
80 String getPackageName() { |
|
81 return packagename; |
|
82 } |
|
83 |
|
84 String getClassFilePathname() { |
|
85 StringBuilder sb = new StringBuilder(paths[0]); |
|
86 for (int i = 1; i < paths.length; i++) { |
|
87 String p = paths[i]; |
|
88 sb.append(File.separator).append(p); |
|
89 } |
|
90 return sb.append(".class").toString(); |
|
91 } |
|
92 |
|
93 boolean isPublic() { |
|
94 return accessFlags == null || accessFlags.is(AccessFlags.ACC_PUBLIC); |
|
95 } |
|
96 |
|
97 Module getModule() { |
|
98 return module; |
|
99 } |
|
100 |
|
101 void setModule(Module m) { |
|
102 if (module != null) { |
|
103 throw new RuntimeException("Module for " + this + " already set"); |
|
104 } |
|
105 this.module = m; |
|
106 } |
|
107 |
|
108 Set<Klass> getReferencedClasses() { |
|
109 return deps.keySet(); |
|
110 } |
|
111 |
|
112 Set<Klass> getReferencingClasses() { |
|
113 return referrers.keySet(); |
|
114 } |
|
115 |
|
116 void setAccessFlags(int flags) { |
|
117 this.accessFlags = new AccessFlags(flags); |
|
118 } |
|
119 |
|
120 void setFileSize(long size) { |
|
121 this.filesize = size; |
|
122 } |
|
123 |
|
124 long getFileSize() { |
|
125 return this.filesize; |
|
126 } |
|
127 |
|
128 boolean exists() { |
|
129 return filesize > 0; |
|
130 } |
|
131 |
|
132 boolean skip(Klass k) { |
|
133 // skip if either class is a root or same class |
|
134 return k.isJavaLangObject || this == k || k.classname.equals(classname); |
|
135 } |
|
136 |
|
137 void addDep(Method callee, ResolutionInfo resInfo) { |
|
138 addDep(callee.getKlass(), resInfo); |
|
139 } |
|
140 |
|
141 void addDep(Klass ref, ResolutionInfo ri) { |
|
142 if (skip(ref)) { |
|
143 return; |
|
144 } |
|
145 Set<ResolutionInfo> resInfos; |
|
146 if (!deps.containsKey(ref)) { |
|
147 resInfos = new TreeSet<ResolutionInfo>(); |
|
148 deps.put(ref, resInfos); |
|
149 } else { |
|
150 resInfos = deps.get(ref); |
|
151 } |
|
152 resInfos.add(ri); |
|
153 } |
|
154 |
|
155 void addReferrer(Method caller, ResolutionInfo resInfo) { |
|
156 addReferrer(caller.getKlass(), resInfo); |
|
157 } |
|
158 |
|
159 void addReferrer(Klass k, ResolutionInfo ri) { |
|
160 if (skip(k)) { |
|
161 return; |
|
162 } |
|
163 Set<ResolutionInfo> resInfos; |
|
164 if (!referrers.containsKey(k)) { |
|
165 resInfos = new TreeSet<ResolutionInfo>(); |
|
166 referrers.put(k, resInfos); |
|
167 } else { |
|
168 resInfos = referrers.get(k); |
|
169 } |
|
170 resInfos.add(ri); |
|
171 } |
|
172 |
|
173 Method getMethod(String name) { |
|
174 return getMethod(name, ""); |
|
175 } |
|
176 |
|
177 Method getMethod(String name, String signature) { |
|
178 Set<Method> set; |
|
179 if (methods.containsKey(name)) { |
|
180 set = methods.get(name); |
|
181 } else { |
|
182 set = new TreeSet<Method>(); |
|
183 methods.put(name, set); |
|
184 } |
|
185 |
|
186 for (Method m : set) { |
|
187 if (m.getName().equals(name) && m.getSignature().equals(signature)) { |
|
188 return m; |
|
189 } |
|
190 } |
|
191 Method m = new Method(this, name, signature); |
|
192 set.add(m); |
|
193 return m; |
|
194 } |
|
195 |
|
196 @Override |
|
197 public String toString() { |
|
198 return classname; |
|
199 } |
|
200 |
|
201 @Override |
|
202 public int compareTo(Klass o) { |
|
203 return classname.compareTo(o.classname); |
|
204 } |
|
205 |
|
206 void addAnnotatedDep(AnnotatedDependency dep) { |
|
207 annotatedDeps.add(dep); |
|
208 } |
|
209 |
|
210 void addClassForNameReference(String method) { |
|
211 classForNameRefs.add(method); |
|
212 } |
|
213 |
|
214 List<AnnotatedDependency> getAnnotatedDeps() { |
|
215 return annotatedDeps; |
|
216 } |
|
217 |
|
218 private static Map<String, Klass> classes = new TreeMap<String, Klass>(); |
|
219 static Set<Klass> getAllClasses() { |
|
220 return new TreeSet<Klass>(classes.values()); |
|
221 } |
|
222 |
|
223 static Klass findKlassFromPathname(String filename) { |
|
224 String name = filename; |
|
225 if (filename.endsWith(".class")) { |
|
226 name = filename.substring(0, filename.length() - 6); |
|
227 } |
|
228 |
|
229 // trim ".class" |
|
230 name = name.replace('/', '.'); |
|
231 for (Klass k : classes.values()) { |
|
232 if (name.endsWith(k.getClassName())) { |
|
233 return k; |
|
234 } |
|
235 } |
|
236 return null; |
|
237 } |
|
238 |
|
239 static Klass findKlass(String classname) { |
|
240 return classes.get(classname); |
|
241 } |
|
242 |
|
243 static Klass getKlass(String name) { |
|
244 Klass k; |
|
245 String classname = name.replace('/', '.'); |
|
246 if (classname.charAt(classname.length() - 1) == ';') { |
|
247 classname = classname.substring(0, classname.length() - 1); |
|
248 } |
|
249 if (classes.containsKey(classname)) { |
|
250 k = classes.get(classname); |
|
251 } else { |
|
252 k = new Klass(classname); |
|
253 classes.put(classname, k); |
|
254 } |
|
255 return k; |
|
256 } |
|
257 |
|
258 public class Method implements Comparable<Method> { |
|
259 |
|
260 private final Klass k; |
|
261 private final String method; |
|
262 private final String signature; |
|
263 private long codeLength; |
|
264 // non-primitive types only |
|
265 private final List<Klass> argTypes; |
|
266 private final Klass returnType; |
|
267 boolean isAbstract = false; |
|
268 boolean marked = false; |
|
269 |
|
270 public Method(Klass k, String method, String signature) { |
|
271 this(k, method, signature, null, null); |
|
272 } |
|
273 |
|
274 public Method(Klass k, String method, String signature, Klass returnType, List<Klass> argTypes) { |
|
275 this.k = k; |
|
276 this.method = method; |
|
277 this.signature = signature; |
|
278 this.argTypes = argTypes; |
|
279 this.returnType = returnType; |
|
280 this.codeLength = 0; |
|
281 } |
|
282 |
|
283 public Klass getKlass() { |
|
284 return k; |
|
285 } |
|
286 |
|
287 public String getName() { |
|
288 return method; |
|
289 } |
|
290 |
|
291 public String getSignature() { |
|
292 return signature; |
|
293 } |
|
294 |
|
295 public Klass getReturnType() { |
|
296 return returnType; |
|
297 } |
|
298 |
|
299 public List<Klass> argTypes() { |
|
300 return argTypes; |
|
301 } |
|
302 |
|
303 public void setCodeLength(long len) { |
|
304 this.codeLength = len; |
|
305 } |
|
306 |
|
307 public long getCodeLength() { |
|
308 return codeLength; |
|
309 } |
|
310 |
|
311 @Override |
|
312 public boolean equals(Object o) { |
|
313 if (o instanceof Method) { |
|
314 return compareTo((Method) o) == 0; |
|
315 } else { |
|
316 return false; |
|
317 } |
|
318 } |
|
319 |
|
320 @Override |
|
321 public int hashCode() { |
|
322 int hash = 3; |
|
323 hash = 71 * hash + (this.k != null ? this.k.hashCode() : 0); |
|
324 hash = 71 * hash + (this.method != null ? this.method.hashCode() : 0); |
|
325 return hash; |
|
326 } |
|
327 |
|
328 @Override |
|
329 public String toString() { |
|
330 if (signature.isEmpty()) { |
|
331 return k.classname + "." + method; |
|
332 } else { |
|
333 return signature; |
|
334 } |
|
335 } |
|
336 |
|
337 public String toHtmlString() { |
|
338 return toString().replace("<", "<").replace(">", ">"); |
|
339 } |
|
340 |
|
341 boolean isClinit() { |
|
342 return method.equals("<clinit>"); |
|
343 } |
|
344 |
|
345 public int compareTo(Method m) { |
|
346 if (k == m.getKlass()) { |
|
347 if (method.equals(m.method)) { |
|
348 return signature.compareTo(m.signature); |
|
349 } else { |
|
350 return method.compareTo(m.method); |
|
351 } |
|
352 } else { |
|
353 return k.compareTo(m.getKlass()); |
|
354 } |
|
355 } |
|
356 } |
|
357 } |
|