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

Mon, 17 Dec 2012 07:47:05 -0800

author
jjg
date
Mon, 17 Dec 2012 07:47:05 -0800
changeset 1455
75ab654b5cd5
parent 1358
fc123bdeddb8
child 1472
0c244701188e
permissions
-rw-r--r--

8004832: Add new doclint package
Reviewed-by: mcimadamore

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

mercurial