src/share/classes/com/sun/tools/classfile/Dependencies.java

Wed, 27 Apr 2016 01:34:52 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:34:52 +0800
changeset 0
959103a6100f
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25 package com.sun.tools.classfile;
aoqi@0 26
aoqi@0 27 import java.util.Deque;
aoqi@0 28 import java.util.HashMap;
aoqi@0 29 import java.util.HashSet;
aoqi@0 30 import java.util.LinkedList;
aoqi@0 31 import java.util.List;
aoqi@0 32 import java.util.Map;
aoqi@0 33 import java.util.Set;
aoqi@0 34 import java.util.regex.Pattern;
aoqi@0 35
aoqi@0 36 import com.sun.tools.classfile.Dependency.Filter;
aoqi@0 37 import com.sun.tools.classfile.Dependency.Finder;
aoqi@0 38 import com.sun.tools.classfile.Dependency.Location;
aoqi@0 39 import com.sun.tools.classfile.Type.ArrayType;
aoqi@0 40 import com.sun.tools.classfile.Type.ClassSigType;
aoqi@0 41 import com.sun.tools.classfile.Type.ClassType;
aoqi@0 42 import com.sun.tools.classfile.Type.MethodType;
aoqi@0 43 import com.sun.tools.classfile.Type.SimpleType;
aoqi@0 44 import com.sun.tools.classfile.Type.TypeParamType;
aoqi@0 45 import com.sun.tools.classfile.Type.WildcardType;
aoqi@0 46 import static com.sun.tools.classfile.ConstantPool.*;
aoqi@0 47
aoqi@0 48 /**
aoqi@0 49 * A framework for determining {@link Dependency dependencies} between class files.
aoqi@0 50 *
aoqi@0 51 * A {@link Dependency.Finder finder} is used to identify the dependencies of
aoqi@0 52 * individual classes. Some finders may return subtypes of {@code Dependency} to
aoqi@0 53 * further characterize the type of dependency, such as a dependency on a
aoqi@0 54 * method within a class.
aoqi@0 55 *
aoqi@0 56 * A {@link Dependency.Filter filter} may be used to restrict the set of
aoqi@0 57 * dependencies found by a finder.
aoqi@0 58 *
aoqi@0 59 * Dependencies that are found may be passed to a {@link Dependencies.Recorder
aoqi@0 60 * recorder} so that the dependencies can be stored in a custom data structure.
aoqi@0 61 */
aoqi@0 62 public class Dependencies {
aoqi@0 63 /**
aoqi@0 64 * Thrown when a class file cannot be found.
aoqi@0 65 */
aoqi@0 66 public static class ClassFileNotFoundException extends Exception {
aoqi@0 67 private static final long serialVersionUID = 3632265927794475048L;
aoqi@0 68
aoqi@0 69 public ClassFileNotFoundException(String className) {
aoqi@0 70 super(className);
aoqi@0 71 this.className = className;
aoqi@0 72 }
aoqi@0 73
aoqi@0 74 public ClassFileNotFoundException(String className, Throwable cause) {
aoqi@0 75 this(className);
aoqi@0 76 initCause(cause);
aoqi@0 77 }
aoqi@0 78
aoqi@0 79 public final String className;
aoqi@0 80 }
aoqi@0 81
aoqi@0 82 /**
aoqi@0 83 * Thrown when an exception is found processing a class file.
aoqi@0 84 */
aoqi@0 85 public static class ClassFileError extends Error {
aoqi@0 86 private static final long serialVersionUID = 4111110813961313203L;
aoqi@0 87
aoqi@0 88 public ClassFileError(Throwable cause) {
aoqi@0 89 initCause(cause);
aoqi@0 90 }
aoqi@0 91 }
aoqi@0 92
aoqi@0 93 /**
aoqi@0 94 * Service provider interface to locate and read class files.
aoqi@0 95 */
aoqi@0 96 public interface ClassFileReader {
aoqi@0 97 /**
aoqi@0 98 * Get the ClassFile object for a specified class.
aoqi@0 99 * @param className the name of the class to be returned.
aoqi@0 100 * @return the ClassFile for the given class
aoqi@0 101 * @throws Dependencies.ClassFileNotFoundException if the classfile cannot be
aoqi@0 102 * found
aoqi@0 103 */
aoqi@0 104 public ClassFile getClassFile(String className)
aoqi@0 105 throws ClassFileNotFoundException;
aoqi@0 106 }
aoqi@0 107
aoqi@0 108 /**
aoqi@0 109 * Service provide interface to handle results.
aoqi@0 110 */
aoqi@0 111 public interface Recorder {
aoqi@0 112 /**
aoqi@0 113 * Record a dependency that has been found.
aoqi@0 114 * @param d
aoqi@0 115 */
aoqi@0 116 public void addDependency(Dependency d);
aoqi@0 117 }
aoqi@0 118
aoqi@0 119 /**
aoqi@0 120 * Get the default finder used to locate the dependencies for a class.
aoqi@0 121 * @return the default finder
aoqi@0 122 */
aoqi@0 123 public static Finder getDefaultFinder() {
aoqi@0 124 return new APIDependencyFinder(AccessFlags.ACC_PRIVATE);
aoqi@0 125 }
aoqi@0 126
aoqi@0 127 /**
aoqi@0 128 * Get a finder used to locate the API dependencies for a class.
aoqi@0 129 * These include the superclass, superinterfaces, and classes referenced in
aoqi@0 130 * the declarations of fields and methods. The fields and methods that
aoqi@0 131 * are checked can be limited according to a specified access.
aoqi@0 132 * The access parameter must be one of {@link AccessFlags#ACC_PUBLIC ACC_PUBLIC},
aoqi@0 133 * {@link AccessFlags#ACC_PRIVATE ACC_PRIVATE},
aoqi@0 134 * {@link AccessFlags#ACC_PROTECTED ACC_PROTECTED}, or 0 for
aoqi@0 135 * package private access. Members with greater than or equal accessibility
aoqi@0 136 * to that specified will be searched for dependencies.
aoqi@0 137 * @param access the access of members to be checked
aoqi@0 138 * @return an API finder
aoqi@0 139 */
aoqi@0 140 public static Finder getAPIFinder(int access) {
aoqi@0 141 return new APIDependencyFinder(access);
aoqi@0 142 }
aoqi@0 143
aoqi@0 144 /**
aoqi@0 145 * Get a finder to do class dependency analysis.
aoqi@0 146 *
aoqi@0 147 * @return a Class dependency finder
aoqi@0 148 */
aoqi@0 149 public static Finder getClassDependencyFinder() {
aoqi@0 150 return new ClassDependencyFinder();
aoqi@0 151 }
aoqi@0 152
aoqi@0 153 /**
aoqi@0 154 * Get the finder used to locate the dependencies for a class.
aoqi@0 155 * @return the finder
aoqi@0 156 */
aoqi@0 157 public Finder getFinder() {
aoqi@0 158 if (finder == null)
aoqi@0 159 finder = getDefaultFinder();
aoqi@0 160 return finder;
aoqi@0 161 }
aoqi@0 162
aoqi@0 163 /**
aoqi@0 164 * Set the finder used to locate the dependencies for a class.
aoqi@0 165 * @param f the finder
aoqi@0 166 */
aoqi@0 167 public void setFinder(Finder f) {
aoqi@0 168 f.getClass(); // null check
aoqi@0 169 finder = f;
aoqi@0 170 }
aoqi@0 171
aoqi@0 172 /**
aoqi@0 173 * Get the default filter used to determine included when searching
aoqi@0 174 * the transitive closure of all the dependencies.
aoqi@0 175 * Unless overridden, the default filter accepts all dependencies.
aoqi@0 176 * @return the default filter.
aoqi@0 177 */
aoqi@0 178 public static Filter getDefaultFilter() {
aoqi@0 179 return DefaultFilter.instance();
aoqi@0 180 }
aoqi@0 181
aoqi@0 182 /**
aoqi@0 183 * Get a filter which uses a regular expression on the target's class name
aoqi@0 184 * to determine if a dependency is of interest.
aoqi@0 185 * @param pattern the pattern used to match the target's class name
aoqi@0 186 * @return a filter for matching the target class name with a regular expression
aoqi@0 187 */
aoqi@0 188 public static Filter getRegexFilter(Pattern pattern) {
aoqi@0 189 return new TargetRegexFilter(pattern);
aoqi@0 190 }
aoqi@0 191
aoqi@0 192 /**
aoqi@0 193 * Get a filter which checks the package of a target's class name
aoqi@0 194 * to determine if a dependency is of interest. The filter checks if the
aoqi@0 195 * package of the target's class matches any of a set of given package
aoqi@0 196 * names. The match may optionally match subpackages of the given names as well.
aoqi@0 197 * @param packageNames the package names used to match the target's class name
aoqi@0 198 * @param matchSubpackages whether or not to match subpackages as well
aoqi@0 199 * @return a filter for checking the target package name against a list of package names
aoqi@0 200 */
aoqi@0 201 public static Filter getPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
aoqi@0 202 return new TargetPackageFilter(packageNames, matchSubpackages);
aoqi@0 203 }
aoqi@0 204
aoqi@0 205 /**
aoqi@0 206 * Get the filter used to determine the dependencies included when searching
aoqi@0 207 * the transitive closure of all the dependencies.
aoqi@0 208 * Unless overridden, the default filter accepts all dependencies.
aoqi@0 209 * @return the filter
aoqi@0 210 */
aoqi@0 211 public Filter getFilter() {
aoqi@0 212 if (filter == null)
aoqi@0 213 filter = getDefaultFilter();
aoqi@0 214 return filter;
aoqi@0 215 }
aoqi@0 216
aoqi@0 217 /**
aoqi@0 218 * Set the filter used to determine the dependencies included when searching
aoqi@0 219 * the transitive closure of all the dependencies.
aoqi@0 220 * @param f the filter
aoqi@0 221 */
aoqi@0 222 public void setFilter(Filter f) {
aoqi@0 223 f.getClass(); // null check
aoqi@0 224 filter = f;
aoqi@0 225 }
aoqi@0 226
aoqi@0 227 /**
aoqi@0 228 * Find the dependencies of a class, using the current
aoqi@0 229 * {@link Dependencies#getFinder finder} and
aoqi@0 230 * {@link Dependencies#getFilter filter}.
aoqi@0 231 * The search may optionally include the transitive closure of all the
aoqi@0 232 * filtered dependencies, by also searching in the classes named in those
aoqi@0 233 * dependencies.
aoqi@0 234 * @param classFinder a finder to locate class files
aoqi@0 235 * @param rootClassNames the names of the root classes from which to begin
aoqi@0 236 * searching
aoqi@0 237 * @param transitiveClosure whether or not to also search those classes
aoqi@0 238 * named in any filtered dependencies that are found.
aoqi@0 239 * @return the set of dependencies that were found
aoqi@0 240 * @throws ClassFileNotFoundException if a required class file cannot be found
aoqi@0 241 * @throws ClassFileError if an error occurs while processing a class file,
aoqi@0 242 * such as an error in the internal class file structure.
aoqi@0 243 */
aoqi@0 244 public Set<Dependency> findAllDependencies(
aoqi@0 245 ClassFileReader classFinder, Set<String> rootClassNames,
aoqi@0 246 boolean transitiveClosure)
aoqi@0 247 throws ClassFileNotFoundException {
aoqi@0 248 final Set<Dependency> results = new HashSet<Dependency>();
aoqi@0 249 Recorder r = new Recorder() {
aoqi@0 250 public void addDependency(Dependency d) {
aoqi@0 251 results.add(d);
aoqi@0 252 }
aoqi@0 253 };
aoqi@0 254 findAllDependencies(classFinder, rootClassNames, transitiveClosure, r);
aoqi@0 255 return results;
aoqi@0 256 }
aoqi@0 257
aoqi@0 258 /**
aoqi@0 259 * Find the dependencies of a class, using the current
aoqi@0 260 * {@link Dependencies#getFinder finder} and
aoqi@0 261 * {@link Dependencies#getFilter filter}.
aoqi@0 262 * The search may optionally include the transitive closure of all the
aoqi@0 263 * filtered dependencies, by also searching in the classes named in those
aoqi@0 264 * dependencies.
aoqi@0 265 * @param classFinder a finder to locate class files
aoqi@0 266 * @param rootClassNames the names of the root classes from which to begin
aoqi@0 267 * searching
aoqi@0 268 * @param transitiveClosure whether or not to also search those classes
aoqi@0 269 * named in any filtered dependencies that are found.
aoqi@0 270 * @param recorder a recorder for handling the results
aoqi@0 271 * @throws ClassFileNotFoundException if a required class file cannot be found
aoqi@0 272 * @throws ClassFileError if an error occurs while processing a class file,
aoqi@0 273 * such as an error in the internal class file structure.
aoqi@0 274 */
aoqi@0 275 public void findAllDependencies(
aoqi@0 276 ClassFileReader classFinder, Set<String> rootClassNames,
aoqi@0 277 boolean transitiveClosure, Recorder recorder)
aoqi@0 278 throws ClassFileNotFoundException {
aoqi@0 279 Set<String> doneClasses = new HashSet<String>();
aoqi@0 280
aoqi@0 281 getFinder(); // ensure initialized
aoqi@0 282 getFilter(); // ensure initialized
aoqi@0 283
aoqi@0 284 // Work queue of names of classfiles to be searched.
aoqi@0 285 // Entries will be unique, and for classes that do not yet have
aoqi@0 286 // dependencies in the results map.
aoqi@0 287 Deque<String> deque = new LinkedList<String>(rootClassNames);
aoqi@0 288
aoqi@0 289 String className;
aoqi@0 290 while ((className = deque.poll()) != null) {
aoqi@0 291 assert (!doneClasses.contains(className));
aoqi@0 292 doneClasses.add(className);
aoqi@0 293
aoqi@0 294 ClassFile cf = classFinder.getClassFile(className);
aoqi@0 295
aoqi@0 296 // The following code just applies the filter to the dependencies
aoqi@0 297 // followed for the transitive closure.
aoqi@0 298 for (Dependency d: finder.findDependencies(cf)) {
aoqi@0 299 recorder.addDependency(d);
aoqi@0 300 if (transitiveClosure && filter.accepts(d)) {
aoqi@0 301 String cn = d.getTarget().getClassName();
aoqi@0 302 if (!doneClasses.contains(cn))
aoqi@0 303 deque.add(cn);
aoqi@0 304 }
aoqi@0 305 }
aoqi@0 306 }
aoqi@0 307 }
aoqi@0 308
aoqi@0 309 private Filter filter;
aoqi@0 310 private Finder finder;
aoqi@0 311
aoqi@0 312 /**
aoqi@0 313 * A location identifying a class.
aoqi@0 314 */
aoqi@0 315 static class SimpleLocation implements Location {
aoqi@0 316 public SimpleLocation(String name) {
aoqi@0 317 this.name = name;
aoqi@0 318 this.className = name.replace('/', '.');
aoqi@0 319 }
aoqi@0 320
aoqi@0 321 public String getName() {
aoqi@0 322 return name;
aoqi@0 323 }
aoqi@0 324
aoqi@0 325 public String getClassName() {
aoqi@0 326 return className;
aoqi@0 327 }
aoqi@0 328
aoqi@0 329 public String getPackageName() {
aoqi@0 330 int i = name.lastIndexOf('/');
aoqi@0 331 return (i > 0) ? name.substring(0, i).replace('/', '.') : "";
aoqi@0 332 }
aoqi@0 333
aoqi@0 334 @Override
aoqi@0 335 public boolean equals(Object other) {
aoqi@0 336 if (this == other)
aoqi@0 337 return true;
aoqi@0 338 if (!(other instanceof SimpleLocation))
aoqi@0 339 return false;
aoqi@0 340 return (name.equals(((SimpleLocation) other).name));
aoqi@0 341 }
aoqi@0 342
aoqi@0 343 @Override
aoqi@0 344 public int hashCode() {
aoqi@0 345 return name.hashCode();
aoqi@0 346 }
aoqi@0 347
aoqi@0 348 @Override
aoqi@0 349 public String toString() {
aoqi@0 350 return name;
aoqi@0 351 }
aoqi@0 352
aoqi@0 353 private String name;
aoqi@0 354 private String className;
aoqi@0 355 }
aoqi@0 356
aoqi@0 357 /**
aoqi@0 358 * A dependency of one class on another.
aoqi@0 359 */
aoqi@0 360 static class SimpleDependency implements Dependency {
aoqi@0 361 public SimpleDependency(Location origin, Location target) {
aoqi@0 362 this.origin = origin;
aoqi@0 363 this.target = target;
aoqi@0 364 }
aoqi@0 365
aoqi@0 366 public Location getOrigin() {
aoqi@0 367 return origin;
aoqi@0 368 }
aoqi@0 369
aoqi@0 370 public Location getTarget() {
aoqi@0 371 return target;
aoqi@0 372 }
aoqi@0 373
aoqi@0 374 @Override
aoqi@0 375 public boolean equals(Object other) {
aoqi@0 376 if (this == other)
aoqi@0 377 return true;
aoqi@0 378 if (!(other instanceof SimpleDependency))
aoqi@0 379 return false;
aoqi@0 380 SimpleDependency o = (SimpleDependency) other;
aoqi@0 381 return (origin.equals(o.origin) && target.equals(o.target));
aoqi@0 382 }
aoqi@0 383
aoqi@0 384 @Override
aoqi@0 385 public int hashCode() {
aoqi@0 386 return origin.hashCode() * 31 + target.hashCode();
aoqi@0 387 }
aoqi@0 388
aoqi@0 389 @Override
aoqi@0 390 public String toString() {
aoqi@0 391 return origin + ":" + target;
aoqi@0 392 }
aoqi@0 393
aoqi@0 394 private Location origin;
aoqi@0 395 private Location target;
aoqi@0 396 }
aoqi@0 397
aoqi@0 398
aoqi@0 399 /**
aoqi@0 400 * This class accepts all dependencies.
aoqi@0 401 */
aoqi@0 402 static class DefaultFilter implements Filter {
aoqi@0 403 private static DefaultFilter instance;
aoqi@0 404
aoqi@0 405 static DefaultFilter instance() {
aoqi@0 406 if (instance == null)
aoqi@0 407 instance = new DefaultFilter();
aoqi@0 408 return instance;
aoqi@0 409 }
aoqi@0 410
aoqi@0 411 public boolean accepts(Dependency dependency) {
aoqi@0 412 return true;
aoqi@0 413 }
aoqi@0 414 }
aoqi@0 415
aoqi@0 416 /**
aoqi@0 417 * This class accepts those dependencies whose target's class name matches a
aoqi@0 418 * regular expression.
aoqi@0 419 */
aoqi@0 420 static class TargetRegexFilter implements Filter {
aoqi@0 421 TargetRegexFilter(Pattern pattern) {
aoqi@0 422 this.pattern = pattern;
aoqi@0 423 }
aoqi@0 424
aoqi@0 425 public boolean accepts(Dependency dependency) {
aoqi@0 426 return pattern.matcher(dependency.getTarget().getClassName()).matches();
aoqi@0 427 }
aoqi@0 428
aoqi@0 429 private final Pattern pattern;
aoqi@0 430 }
aoqi@0 431
aoqi@0 432 /**
aoqi@0 433 * This class accepts those dependencies whose class name is in a given
aoqi@0 434 * package.
aoqi@0 435 */
aoqi@0 436 static class TargetPackageFilter implements Filter {
aoqi@0 437 TargetPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
aoqi@0 438 for (String pn: packageNames) {
aoqi@0 439 if (pn.length() == 0) // implies null check as well
aoqi@0 440 throw new IllegalArgumentException();
aoqi@0 441 }
aoqi@0 442 this.packageNames = packageNames;
aoqi@0 443 this.matchSubpackages = matchSubpackages;
aoqi@0 444 }
aoqi@0 445
aoqi@0 446 public boolean accepts(Dependency dependency) {
aoqi@0 447 String pn = dependency.getTarget().getPackageName();
aoqi@0 448 if (packageNames.contains(pn))
aoqi@0 449 return true;
aoqi@0 450
aoqi@0 451 if (matchSubpackages) {
aoqi@0 452 for (String n: packageNames) {
aoqi@0 453 if (pn.startsWith(n + "."))
aoqi@0 454 return true;
aoqi@0 455 }
aoqi@0 456 }
aoqi@0 457
aoqi@0 458 return false;
aoqi@0 459 }
aoqi@0 460
aoqi@0 461 private final Set<String> packageNames;
aoqi@0 462 private final boolean matchSubpackages;
aoqi@0 463 }
aoqi@0 464
aoqi@0 465 /**
aoqi@0 466 * This class identifies class names directly or indirectly in the constant pool.
aoqi@0 467 */
aoqi@0 468 static class ClassDependencyFinder extends BasicDependencyFinder {
aoqi@0 469 public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
aoqi@0 470 Visitor v = new Visitor(classfile);
aoqi@0 471 for (CPInfo cpInfo: classfile.constant_pool.entries()) {
aoqi@0 472 v.scan(cpInfo);
aoqi@0 473 }
aoqi@0 474 try {
aoqi@0 475 v.addClass(classfile.super_class);
aoqi@0 476 v.addClasses(classfile.interfaces);
aoqi@0 477 v.scan(classfile.attributes);
aoqi@0 478
aoqi@0 479 for (Field f : classfile.fields) {
aoqi@0 480 v.scan(f.descriptor, f.attributes);
aoqi@0 481 }
aoqi@0 482 for (Method m : classfile.methods) {
aoqi@0 483 v.scan(m.descriptor, m.attributes);
aoqi@0 484 Exceptions_attribute e =
aoqi@0 485 (Exceptions_attribute)m.attributes.get(Attribute.Exceptions);
aoqi@0 486 if (e != null) {
aoqi@0 487 v.addClasses(e.exception_index_table);
aoqi@0 488 }
aoqi@0 489 }
aoqi@0 490 } catch (ConstantPoolException e) {
aoqi@0 491 throw new ClassFileError(e);
aoqi@0 492 }
aoqi@0 493
aoqi@0 494 return v.deps;
aoqi@0 495 }
aoqi@0 496 }
aoqi@0 497
aoqi@0 498 /**
aoqi@0 499 * This class identifies class names in the signatures of classes, fields,
aoqi@0 500 * and methods in a class.
aoqi@0 501 */
aoqi@0 502 static class APIDependencyFinder extends BasicDependencyFinder {
aoqi@0 503 APIDependencyFinder(int access) {
aoqi@0 504 switch (access) {
aoqi@0 505 case AccessFlags.ACC_PUBLIC:
aoqi@0 506 case AccessFlags.ACC_PROTECTED:
aoqi@0 507 case AccessFlags.ACC_PRIVATE:
aoqi@0 508 case 0:
aoqi@0 509 showAccess = access;
aoqi@0 510 break;
aoqi@0 511 default:
aoqi@0 512 throw new IllegalArgumentException("invalid access 0x"
aoqi@0 513 + Integer.toHexString(access));
aoqi@0 514 }
aoqi@0 515 }
aoqi@0 516
aoqi@0 517 public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
aoqi@0 518 try {
aoqi@0 519 Visitor v = new Visitor(classfile);
aoqi@0 520 v.addClass(classfile.super_class);
aoqi@0 521 v.addClasses(classfile.interfaces);
aoqi@0 522 // inner classes?
aoqi@0 523 for (Field f : classfile.fields) {
aoqi@0 524 if (checkAccess(f.access_flags))
aoqi@0 525 v.scan(f.descriptor, f.attributes);
aoqi@0 526 }
aoqi@0 527 for (Method m : classfile.methods) {
aoqi@0 528 if (checkAccess(m.access_flags)) {
aoqi@0 529 v.scan(m.descriptor, m.attributes);
aoqi@0 530 Exceptions_attribute e =
aoqi@0 531 (Exceptions_attribute) m.attributes.get(Attribute.Exceptions);
aoqi@0 532 if (e != null)
aoqi@0 533 v.addClasses(e.exception_index_table);
aoqi@0 534 }
aoqi@0 535 }
aoqi@0 536 return v.deps;
aoqi@0 537 } catch (ConstantPoolException e) {
aoqi@0 538 throw new ClassFileError(e);
aoqi@0 539 }
aoqi@0 540 }
aoqi@0 541
aoqi@0 542 boolean checkAccess(AccessFlags flags) {
aoqi@0 543 // code copied from javap.Options.checkAccess
aoqi@0 544 boolean isPublic = flags.is(AccessFlags.ACC_PUBLIC);
aoqi@0 545 boolean isProtected = flags.is(AccessFlags.ACC_PROTECTED);
aoqi@0 546 boolean isPrivate = flags.is(AccessFlags.ACC_PRIVATE);
aoqi@0 547 boolean isPackage = !(isPublic || isProtected || isPrivate);
aoqi@0 548
aoqi@0 549 if ((showAccess == AccessFlags.ACC_PUBLIC) && (isProtected || isPrivate || isPackage))
aoqi@0 550 return false;
aoqi@0 551 else if ((showAccess == AccessFlags.ACC_PROTECTED) && (isPrivate || isPackage))
aoqi@0 552 return false;
aoqi@0 553 else if ((showAccess == 0) && (isPrivate))
aoqi@0 554 return false;
aoqi@0 555 else
aoqi@0 556 return true;
aoqi@0 557 }
aoqi@0 558
aoqi@0 559 private int showAccess;
aoqi@0 560 }
aoqi@0 561
aoqi@0 562 static abstract class BasicDependencyFinder implements Finder {
aoqi@0 563 private Map<String,Location> locations = new HashMap<String,Location>();
aoqi@0 564
aoqi@0 565 Location getLocation(String className) {
aoqi@0 566 Location l = locations.get(className);
aoqi@0 567 if (l == null)
aoqi@0 568 locations.put(className, l = new SimpleLocation(className));
aoqi@0 569 return l;
aoqi@0 570 }
aoqi@0 571
aoqi@0 572 class Visitor implements ConstantPool.Visitor<Void,Void>, Type.Visitor<Void, Void> {
aoqi@0 573 private ConstantPool constant_pool;
aoqi@0 574 private Location origin;
aoqi@0 575 Set<Dependency> deps;
aoqi@0 576
aoqi@0 577 Visitor(ClassFile classFile) {
aoqi@0 578 try {
aoqi@0 579 constant_pool = classFile.constant_pool;
aoqi@0 580 origin = getLocation(classFile.getName());
aoqi@0 581 deps = new HashSet<Dependency>();
aoqi@0 582 } catch (ConstantPoolException e) {
aoqi@0 583 throw new ClassFileError(e);
aoqi@0 584 }
aoqi@0 585 }
aoqi@0 586
aoqi@0 587 void scan(Descriptor d, Attributes attrs) {
aoqi@0 588 try {
aoqi@0 589 scan(new Signature(d.index).getType(constant_pool));
aoqi@0 590 scan(attrs);
aoqi@0 591 } catch (ConstantPoolException e) {
aoqi@0 592 throw new ClassFileError(e);
aoqi@0 593 }
aoqi@0 594 }
aoqi@0 595
aoqi@0 596 void scan(CPInfo cpInfo) {
aoqi@0 597 cpInfo.accept(this, null);
aoqi@0 598 }
aoqi@0 599
aoqi@0 600 void scan(Type t) {
aoqi@0 601 t.accept(this, null);
aoqi@0 602 }
aoqi@0 603
aoqi@0 604 void scan(Attributes attrs) {
aoqi@0 605 try {
aoqi@0 606 Signature_attribute sa = (Signature_attribute)attrs.get(Attribute.Signature);
aoqi@0 607 if (sa != null)
aoqi@0 608 scan(sa.getParsedSignature().getType(constant_pool));
aoqi@0 609
aoqi@0 610 scan((RuntimeVisibleAnnotations_attribute)
aoqi@0 611 attrs.get(Attribute.RuntimeVisibleAnnotations));
aoqi@0 612 scan((RuntimeVisibleParameterAnnotations_attribute)
aoqi@0 613 attrs.get(Attribute.RuntimeVisibleParameterAnnotations));
aoqi@0 614 } catch (ConstantPoolException e) {
aoqi@0 615 throw new ClassFileError(e);
aoqi@0 616 }
aoqi@0 617 }
aoqi@0 618
aoqi@0 619 private void scan(RuntimeAnnotations_attribute attr) throws ConstantPoolException {
aoqi@0 620 if (attr == null) {
aoqi@0 621 return;
aoqi@0 622 }
aoqi@0 623 for (int i = 0; i < attr.annotations.length; i++) {
aoqi@0 624 int index = attr.annotations[i].type_index;
aoqi@0 625 scan(new Signature(index).getType(constant_pool));
aoqi@0 626 }
aoqi@0 627 }
aoqi@0 628
aoqi@0 629 private void scan(RuntimeParameterAnnotations_attribute attr) throws ConstantPoolException {
aoqi@0 630 if (attr == null) {
aoqi@0 631 return;
aoqi@0 632 }
aoqi@0 633 for (int param = 0; param < attr.parameter_annotations.length; param++) {
aoqi@0 634 for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
aoqi@0 635 int index = attr.parameter_annotations[param][i].type_index;
aoqi@0 636 scan(new Signature(index).getType(constant_pool));
aoqi@0 637 }
aoqi@0 638 }
aoqi@0 639 }
aoqi@0 640
aoqi@0 641 void addClass(int index) throws ConstantPoolException {
aoqi@0 642 if (index != 0) {
aoqi@0 643 String name = constant_pool.getClassInfo(index).getBaseName();
aoqi@0 644 if (name != null)
aoqi@0 645 addDependency(name);
aoqi@0 646 }
aoqi@0 647 }
aoqi@0 648
aoqi@0 649 void addClasses(int[] indices) throws ConstantPoolException {
aoqi@0 650 for (int i: indices)
aoqi@0 651 addClass(i);
aoqi@0 652 }
aoqi@0 653
aoqi@0 654 private void addDependency(String name) {
aoqi@0 655 deps.add(new SimpleDependency(origin, getLocation(name)));
aoqi@0 656 }
aoqi@0 657
aoqi@0 658 // ConstantPool.Visitor methods
aoqi@0 659
aoqi@0 660 public Void visitClass(CONSTANT_Class_info info, Void p) {
aoqi@0 661 try {
aoqi@0 662 if (info.getName().startsWith("["))
aoqi@0 663 new Signature(info.name_index).getType(constant_pool).accept(this, null);
aoqi@0 664 else
aoqi@0 665 addDependency(info.getBaseName());
aoqi@0 666 return null;
aoqi@0 667 } catch (ConstantPoolException e) {
aoqi@0 668 throw new ClassFileError(e);
aoqi@0 669 }
aoqi@0 670 }
aoqi@0 671
aoqi@0 672 public Void visitDouble(CONSTANT_Double_info info, Void p) {
aoqi@0 673 return null;
aoqi@0 674 }
aoqi@0 675
aoqi@0 676 public Void visitFieldref(CONSTANT_Fieldref_info info, Void p) {
aoqi@0 677 return visitRef(info, p);
aoqi@0 678 }
aoqi@0 679
aoqi@0 680 public Void visitFloat(CONSTANT_Float_info info, Void p) {
aoqi@0 681 return null;
aoqi@0 682 }
aoqi@0 683
aoqi@0 684 public Void visitInteger(CONSTANT_Integer_info info, Void p) {
aoqi@0 685 return null;
aoqi@0 686 }
aoqi@0 687
aoqi@0 688 public Void visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
aoqi@0 689 return visitRef(info, p);
aoqi@0 690 }
aoqi@0 691
aoqi@0 692 public Void visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
aoqi@0 693 return null;
aoqi@0 694 }
aoqi@0 695
aoqi@0 696 public Void visitLong(CONSTANT_Long_info info, Void p) {
aoqi@0 697 return null;
aoqi@0 698 }
aoqi@0 699
aoqi@0 700 public Void visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
aoqi@0 701 return null;
aoqi@0 702 }
aoqi@0 703
aoqi@0 704 public Void visitMethodType(CONSTANT_MethodType_info info, Void p) {
aoqi@0 705 return null;
aoqi@0 706 }
aoqi@0 707
aoqi@0 708 public Void visitMethodref(CONSTANT_Methodref_info info, Void p) {
aoqi@0 709 return visitRef(info, p);
aoqi@0 710 }
aoqi@0 711
aoqi@0 712 public Void visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
aoqi@0 713 try {
aoqi@0 714 new Signature(info.type_index).getType(constant_pool).accept(this, null);
aoqi@0 715 return null;
aoqi@0 716 } catch (ConstantPoolException e) {
aoqi@0 717 throw new ClassFileError(e);
aoqi@0 718 }
aoqi@0 719 }
aoqi@0 720
aoqi@0 721 public Void visitString(CONSTANT_String_info info, Void p) {
aoqi@0 722 return null;
aoqi@0 723 }
aoqi@0 724
aoqi@0 725 public Void visitUtf8(CONSTANT_Utf8_info info, Void p) {
aoqi@0 726 return null;
aoqi@0 727 }
aoqi@0 728
aoqi@0 729 private Void visitRef(CPRefInfo info, Void p) {
aoqi@0 730 try {
aoqi@0 731 visitClass(info.getClassInfo(), p);
aoqi@0 732 return null;
aoqi@0 733 } catch (ConstantPoolException e) {
aoqi@0 734 throw new ClassFileError(e);
aoqi@0 735 }
aoqi@0 736 }
aoqi@0 737
aoqi@0 738 // Type.Visitor methods
aoqi@0 739
aoqi@0 740 private void findDependencies(Type t) {
aoqi@0 741 if (t != null)
aoqi@0 742 t.accept(this, null);
aoqi@0 743 }
aoqi@0 744
aoqi@0 745 private void findDependencies(List<? extends Type> ts) {
aoqi@0 746 if (ts != null) {
aoqi@0 747 for (Type t: ts)
aoqi@0 748 t.accept(this, null);
aoqi@0 749 }
aoqi@0 750 }
aoqi@0 751
aoqi@0 752 public Void visitSimpleType(SimpleType type, Void p) {
aoqi@0 753 return null;
aoqi@0 754 }
aoqi@0 755
aoqi@0 756 public Void visitArrayType(ArrayType type, Void p) {
aoqi@0 757 findDependencies(type.elemType);
aoqi@0 758 return null;
aoqi@0 759 }
aoqi@0 760
aoqi@0 761 public Void visitMethodType(MethodType type, Void p) {
aoqi@0 762 findDependencies(type.paramTypes);
aoqi@0 763 findDependencies(type.returnType);
aoqi@0 764 findDependencies(type.throwsTypes);
aoqi@0 765 findDependencies(type.typeParamTypes);
aoqi@0 766 return null;
aoqi@0 767 }
aoqi@0 768
aoqi@0 769 public Void visitClassSigType(ClassSigType type, Void p) {
aoqi@0 770 findDependencies(type.superclassType);
aoqi@0 771 findDependencies(type.superinterfaceTypes);
aoqi@0 772 return null;
aoqi@0 773 }
aoqi@0 774
aoqi@0 775 public Void visitClassType(ClassType type, Void p) {
aoqi@0 776 findDependencies(type.outerType);
aoqi@0 777 addDependency(type.getBinaryName());
aoqi@0 778 findDependencies(type.typeArgs);
aoqi@0 779 return null;
aoqi@0 780 }
aoqi@0 781
aoqi@0 782 public Void visitTypeParamType(TypeParamType type, Void p) {
aoqi@0 783 findDependencies(type.classBound);
aoqi@0 784 findDependencies(type.interfaceBounds);
aoqi@0 785 return null;
aoqi@0 786 }
aoqi@0 787
aoqi@0 788 public Void visitWildcardType(WildcardType type, Void p) {
aoqi@0 789 findDependencies(type.boundType);
aoqi@0 790 return null;
aoqi@0 791 }
aoqi@0 792 }
aoqi@0 793 }
aoqi@0 794 }

mercurial