/* * @(#)ClassUseMapper.java 1.2 98/06/30 * * Copyright 1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. */ package com.sun.tools.doclets.standard; import com.sun.javadoc.*; import com.sun.tools.doclets.ClassTree; import com.sun.tools.doclets.DocletAbortException; import java.util.*; /** * @since JDK1.2 * @author Robert G. Field */ public class ClassUseMapper { private final ClassTree classtree; /** * Mapping of ClassDocs to set of PackageDoc used by that class. * Entries may be null. */ public Map classToPackage = new HashMap(); /** * Mapping of ClassDocs to set of ClassDoc used by that class. * Entries may be null. */ public Map classToClass = new HashMap(); /** * Mapping of ClassDocs to list of ClassDoc which are direct or * indirect subclasses of that class. * Entries may be null. */ public Map classToSubclass = new HashMap(); /** * Mapping of ClassDocs to list of ClassDoc which are direct or * indirect subinterfaces of that interface. * Entries may be null. */ public Map classToSubinterface = new HashMap(); /** * Mapping of ClassDocs to list of ClassDoc which implement * this interface. * Entries may be null. */ public Map classToImplementingClass = new HashMap(); /** * Mapping of ClassDocs to list of FieldDoc declared as that class. * Entries may be null. */ public Map classToField = new HashMap(); /** * Mapping of ClassDocs to list of MethodDoc returning that class. * Entries may be null. */ public Map classToMethodReturn = new HashMap(); /** * Mapping of ClassDocs to list of MethodDoc having that class * as an arg. * Entries may be null. */ public Map classToMethodArgs = new HashMap(); /** * Mapping of ClassDocs to list of MethodDoc which throws that class. * Entries may be null. */ public Map classToMethodThrows = new HashMap(); /** * Mapping of ClassDocs to list of ConstructorDoc having that class * as an arg. * Entries may be null. */ public Map classToConstructorArgs = new HashMap(); /** * Mapping of ClassDocs to list of ConstructorDoc which throws that class. * Entries may be null. */ public Map classToConstructorThrows = new HashMap(); /** * Write out class use pages. */ public static void generate(RootDoc root, ClassTree classtree) throws DocletAbortException { ClassUseMapper mapper = new ClassUseMapper(root, classtree); ClassDoc[] classes = root.classes(); for (int i = 0; i < classes.length; i++) { ClassUseWriter.generate(mapper, classes[i]); } PackageDoc[] pkgs = Standard.configuration().packages; for (int i = 0; i < pkgs.length; i++) { PackageUseWriter.generate(mapper, pkgs[i]); } } private ClassUseMapper(RootDoc root, ClassTree classtree) { this.classtree = classtree; // Map subclassing, subinterfacing implementing, ... for (Iterator it = classtree.baseclasses().iterator(); it.hasNext();) { subclasses((ClassDoc)it.next()); } for (Iterator it = classtree.baseinterfaces().iterator(); it.hasNext();) { // does subinterfacing as side-effect implementingClasses((ClassDoc)it.next()); } // Map methods, fields, constructors using a class. ClassDoc[] classes = root.classes(); for (int i = 0; i < classes.length; i++) { ClassDoc cd = classes[i]; FieldDoc[] fields = cd.fields(); for (int j = 0; j < fields.length; j++) { FieldDoc fd = fields[j]; ClassDoc tcd = fd.type().asClassDoc(); if (tcd != null) { add(classToField, tcd, fd); } } ConstructorDoc[] cons = cd.constructors(); for (int j = 0; j < cons.length; j++) { mapExecutable(cons[j]); } MethodDoc[] meths = cd.methods(); for (int j = 0; j < meths.length; j++) { MethodDoc md = meths[j]; mapExecutable(md); ClassDoc tcd = md.returnType().asClassDoc(); if (tcd != null) { add(classToMethodReturn, tcd, md); } } } } /** * Return all subclasses of a class AND fill-in classToSubclass map. */ private Collection subclasses(ClassDoc cd) { Collection ret = (Collection)classToSubclass.get(cd); if (ret == null) { ret = new TreeSet(); List subs = classtree.subclasses(cd); if (subs != null) { ret.addAll(subs); for (Iterator it = subs.iterator(); it.hasNext();) { ret.addAll(subclasses((ClassDoc)it.next())); } } addAll(classToSubclass, cd, ret); } return ret; } /** * Return all subinterfaces of an interface AND fill-in classToSubinterface map. */ private Collection subinterfaces(ClassDoc cd) { Collection ret = (Collection)classToSubinterface.get(cd); if (ret == null) { ret = new TreeSet(); List subs = classtree.subinterfaces(cd); if (subs != null) { ret.addAll(subs); for (Iterator it = subs.iterator(); it.hasNext();) { ret.addAll(subinterfaces((ClassDoc)it.next())); } } addAll(classToSubinterface, cd, ret); } return ret; } /** * Return all implementing classes of an interface (including * all subclasses of implementing classes and all classes * implementing subinterfaces) AND fill-in both classToImplementingClass * and classToSubinterface maps. */ private Collection implementingClasses(ClassDoc cd) { Collection ret = (List)classToImplementingClass.get(cd); if (ret == null) { ret = new TreeSet(); List impl = classtree.implementingclasses(cd); if (impl != null) { ret.addAll(impl); for (Iterator it = impl.iterator(); it.hasNext();) { ret.addAll(subclasses((ClassDoc)it.next())); } } for (Iterator it = subinterfaces(cd).iterator(); it.hasNext();) { ret.addAll(implementingClasses((ClassDoc)it.next())); } addAll(classToImplementingClass, cd, ret); } return ret; } /** * Determine classes used by a method or constructor, so they can be * inverse mapped. */ private void mapExecutable(ExecutableMemberDoc em) { Parameter[] params = em.parameters(); boolean isConstructor = em.isConstructor(); List classArgs = new ArrayList(); for (int k = 0; k < params.length; k++) { ClassDoc pcd = params[k].type().asClassDoc(); // primitives don't get mapped, also avoid dups if (pcd != null && !classArgs.contains(pcd)) { add(isConstructor? classToConstructorArgs :classToMethodArgs, pcd, em); classArgs.add(pcd); } } ClassDoc[] thr = em.thrownExceptions(); for (int k = 0; k < thr.length; k++) { add(isConstructor? classToConstructorThrows : classToMethodThrows, thr[k], em); } } private List refList(Map map, ClassDoc cd) { List list = (List)map.get(cd); if (list == null) { list = new ArrayList(); map.put(cd, list); } return list; } private Set packageSet(ClassDoc cd) { Set pkgSet = (Set)classToPackage.get(cd); if (pkgSet == null) { pkgSet = new TreeSet(); classToPackage.put(cd, pkgSet); } return pkgSet; } private Set classSet(ClassDoc cd) { Set clsSet = (Set)classToClass.get(cd); if (clsSet == null) { clsSet = new TreeSet(); classToClass.put(cd, clsSet); } return clsSet; } private void add(Map map, ClassDoc cd, ProgramElementDoc ref) { // add to specified map refList(map, cd).add(ref); // add ref's package to package map and class map packageSet(cd).add(ref.containingPackage()); classSet(cd).add(ref instanceof MemberDoc? ((MemberDoc)ref).containingClass() : ref); } private void addAll(Map map, ClassDoc cd, Collection refs) { if (refs == null) { return; } // add to specified map refList(map, cd).addAll(refs); Set pkgSet = packageSet(cd); Set clsSet = classSet(cd); // add ref's package to package map and class map for (Iterator it = refs.iterator(); it.hasNext();) { ProgramElementDoc pedoc = (ProgramElementDoc)it.next(); pkgSet.add(pedoc.containingPackage()); clsSet.add(pedoc instanceof MemberDoc? ((MemberDoc)pedoc).containingClass() : pedoc); } } }