jdk/make/modules/tools/src/com/sun/classanalyzer/Klass.java
changeset 8852 c228cf346138
parent 8851 e630c590eb10
parent 8717 f75a1efb1412
child 8853 6aa795396cc8
child 9067 c0b85430843d
equal deleted inserted replaced
8851:e630c590eb10 8852:c228cf346138
     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("<", "&lt;").replace(">", "&gt;");
       
   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 }