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

Wed, 02 Jun 2010 19:08:47 -0700

author
darcy
date
Wed, 02 Jun 2010 19:08:47 -0700
changeset 575
9a7c998bf2fc
parent 554
9d9f26857129
child 826
5cf6c432ef2f
permissions
-rw-r--r--

6933147: Provided new utility visitors supporting SourceVersion.RELEASE_7
Reviewed-by: jjg

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

mercurial