001    /*
002     * Copyright 1998-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.doclets.internal.toolkit.util;
027    
028    import com.sun.javadoc.*;
029    import java.util.*;
030    
031    /**
032     * Map all class uses for a given class.
033     *
034     * This code is not part of an API.
035     * It is implementation that is subject to change.
036     * Do not use it as an API
037     *
038     * @since 1.2
039     * @author Robert G. Field
040     */
041    public class ClassUseMapper {
042    
043        private final ClassTree classtree;
044    
045        /**
046         * Mapping of ClassDocs to set of PackageDoc used by that class.
047         * Entries may be null.
048         */
049        public Map<String,Set<PackageDoc>> classToPackage = new HashMap<String,Set<PackageDoc>>();
050    
051        /**
052         * Mapping of Annotations to set of PackageDoc that use the annotation.
053         */
054        public Map<String,List<PackageDoc>> classToPackageAnnotations = new HashMap<String,List<PackageDoc>>();
055    
056        /**
057         * Mapping of ClassDocs to set of ClassDoc used by that class.
058         * Entries may be null.
059         */
060        public Map<String,Set<ClassDoc>> classToClass = new HashMap<String,Set<ClassDoc>>();
061    
062        /**
063         * Mapping of ClassDocs to list of ClassDoc which are direct or
064         * indirect subclasses of that class.
065         * Entries may be null.
066         */
067        public Map<String,List<ClassDoc>> classToSubclass = new HashMap<String,List<ClassDoc>>();
068    
069        /**
070         * Mapping of ClassDocs to list of ClassDoc which are direct or
071         * indirect subinterfaces of that interface.
072         * Entries may be null.
073         */
074        public Map<String,List<ClassDoc>> classToSubinterface = new HashMap<String,List<ClassDoc>>();
075    
076        /**
077         * Mapping of ClassDocs to list of ClassDoc which implement
078         * this interface.
079         * Entries may be null.
080         */
081        public Map<String,List<ClassDoc>> classToImplementingClass = new HashMap<String,List<ClassDoc>>();
082    
083        /**
084         * Mapping of ClassDocs to list of FieldDoc declared as that class.
085         * Entries may be null.
086         */
087        public Map<String,List<FieldDoc>> classToField = new HashMap<String,List<FieldDoc>>();
088    
089        /**
090         * Mapping of ClassDocs to list of MethodDoc returning that class.
091         * Entries may be null.
092         */
093        public Map<String,List<MethodDoc>> classToMethodReturn = new HashMap<String,List<MethodDoc>>();
094    
095        /**
096         * Mapping of ClassDocs to list of MethodDoc having that class
097         * as an arg.
098         * Entries may be null.
099         */
100        public Map<String,List<ExecutableMemberDoc>> classToMethodArgs = new HashMap<String,List<ExecutableMemberDoc>>();
101    
102        /**
103         * Mapping of ClassDocs to list of MethodDoc which throws that class.
104         * Entries may be null.
105         */
106        public Map<String,List<ExecutableMemberDoc>> classToMethodThrows = new HashMap<String,List<ExecutableMemberDoc>>();
107    
108        /**
109         * Mapping of ClassDocs to list of ConstructorDoc having that class
110         * as an arg.
111         * Entries may be null.
112         */
113        public Map<String,List<ExecutableMemberDoc>> classToConstructorArgs = new HashMap<String,List<ExecutableMemberDoc>>();
114    
115        /**
116         * Mapping of ClassDocs to list of ConstructorDoc which throws that class.
117         * Entries may be null.
118         */
119        public Map<String,List<ExecutableMemberDoc>> classToConstructorThrows = new HashMap<String,List<ExecutableMemberDoc>>();
120    
121        /**
122         * The mapping of AnnotationTypeDocs to constructors that use them.
123         */
124        public Map<String,List<ConstructorDoc>> classToConstructorAnnotations = new HashMap<String,List<ConstructorDoc>>();
125    
126        /**
127         * The mapping of AnnotationTypeDocs to Constructor parameters that use them.
128         */
129        public Map<String,List<ExecutableMemberDoc>> classToConstructorParamAnnotation = new HashMap<String,List<ExecutableMemberDoc>>();
130    
131        /**
132         * The mapping of ClassDocs to Constructor arguments that use them as type parameters.
133         */
134        public Map<String,List<ExecutableMemberDoc>> classToConstructorDocArgTypeParam = new HashMap<String,List<ExecutableMemberDoc>>();
135    
136        /**
137         * The mapping of ClassDocs to ClassDocs that use them as type parameters.
138         */
139        public Map<String,List<ClassDoc>> classToClassTypeParam = new HashMap<String,List<ClassDoc>>();
140    
141        /**
142         * The mapping of AnnotationTypeDocs to ClassDocs that use them.
143         */
144        public Map<String,List<ClassDoc>> classToClassAnnotations = new HashMap<String,List<ClassDoc>>();
145    
146        /**
147         * The mapping of ClassDocs to ExecutableMemberDocs that use them as type parameters.
148         */
149        public Map<String,List<MethodDoc>> classToExecMemberDocTypeParam = new HashMap<String,List<MethodDoc>>();
150    
151        /**
152         * The mapping of ClassDocs to ExecutableMemberDocs arguments that use them as type parameters.
153         */
154        public Map<String,List<ExecutableMemberDoc>> classToExecMemberDocArgTypeParam = new HashMap<String,List<ExecutableMemberDoc>>();
155    
156        /**
157         * The mapping of AnnotationTypeDocs to ExecutableMemberDocs that use them.
158         */
159        public Map<String,List<MethodDoc>> classToExecMemberDocAnnotations = new HashMap<String,List<MethodDoc>>();
160    
161        /**
162         * The mapping of ClassDocs to ExecutableMemberDocs that have return type
163         * with type parameters of that class.
164         */
165        public Map<String,List<MethodDoc>> classToExecMemberDocReturnTypeParam = new HashMap<String,List<MethodDoc>>();
166    
167        /**
168         * The mapping of AnnotationTypeDocs to MethodDoc parameters that use them.
169         */
170        public Map<String,List<ExecutableMemberDoc>> classToExecMemberDocParamAnnotation = new HashMap<String,List<ExecutableMemberDoc>>();
171    
172        /**
173         * The mapping of ClassDocs to FieldDocs that use them as type parameters.
174         */
175        public Map<String,List<FieldDoc>> classToFieldDocTypeParam = new HashMap<String,List<FieldDoc>>();
176    
177        /**
178         * The mapping of AnnotationTypeDocs to FieldDocs that use them.
179         */
180        public Map<String,List<FieldDoc>> annotationToFieldDoc = new HashMap<String,List<FieldDoc>>();
181    
182    
183        public ClassUseMapper(RootDoc root, ClassTree classtree) {
184            this.classtree = classtree;
185    
186            // Map subclassing, subinterfacing implementing, ...
187            for (Iterator<ClassDoc> it = classtree.baseclasses().iterator(); it.hasNext();) {
188                subclasses(it.next());
189            }
190            for (Iterator<ClassDoc> it = classtree.baseinterfaces().iterator(); it.hasNext();) {
191                // does subinterfacing as side-effect
192                implementingClasses(it.next());
193            }
194            // Map methods, fields, constructors using a class.
195            ClassDoc[] classes = root.classes();
196            for (int i = 0; i < classes.length; i++) {
197                PackageDoc pkg = classes[i].containingPackage();
198                mapAnnotations(classToPackageAnnotations, pkg, pkg);
199                ClassDoc cd = classes[i];
200                mapTypeParameters(classToClassTypeParam, cd, cd);
201                mapAnnotations(classToClassAnnotations, cd, cd);
202                FieldDoc[] fields = cd.fields();
203                for (int j = 0; j < fields.length; j++) {
204                    FieldDoc fd = fields[j];
205                    mapTypeParameters(classToFieldDocTypeParam, fd, fd);
206                    mapAnnotations(annotationToFieldDoc, fd, fd);
207                    if (! fd.type().isPrimitive()) {
208                        add(classToField, fd.type().asClassDoc(), fd);
209                    }
210                }
211                ConstructorDoc[] cons = cd.constructors();
212                for (int j = 0; j < cons.length; j++) {
213                    mapAnnotations(classToConstructorAnnotations, cons[j], cons[j]);
214                    mapExecutable(cons[j]);
215                }
216                MethodDoc[] meths = cd.methods();
217                for (int j = 0; j < meths.length; j++) {
218                    MethodDoc md = meths[j];
219                    mapExecutable(md);
220                    mapTypeParameters(classToExecMemberDocTypeParam, md, md);
221                    mapAnnotations(classToExecMemberDocAnnotations, md, md);
222                    if (! (md.returnType().isPrimitive() || md.returnType() instanceof TypeVariable)) {
223                        mapTypeParameters(classToExecMemberDocReturnTypeParam,
224                            md.returnType(), md);
225                        add(classToMethodReturn, md.returnType().asClassDoc(), md);
226                    }
227                }
228            }
229        }
230    
231        /**
232         * Return all subclasses of a class AND fill-in classToSubclass map.
233         */
234        private Collection<ClassDoc> subclasses(ClassDoc cd) {
235            Collection<ClassDoc> ret = classToSubclass.get(cd.qualifiedName());
236            if (ret == null) {
237                ret = new TreeSet<ClassDoc>();
238                List<ClassDoc> subs = classtree.subclasses(cd);
239                if (subs != null) {
240                    ret.addAll(subs);
241                    for (Iterator<ClassDoc> it = subs.iterator(); it.hasNext();) {
242                        ret.addAll(subclasses(it.next()));
243                    }
244                }
245                addAll(classToSubclass, cd, ret);
246            }
247            return ret;
248        }
249    
250        /**
251         * Return all subinterfaces of an interface AND fill-in classToSubinterface map.
252         */
253        private Collection<ClassDoc> subinterfaces(ClassDoc cd) {
254            Collection<ClassDoc> ret = classToSubinterface.get(cd.qualifiedName());
255            if (ret == null) {
256                ret = new TreeSet<ClassDoc>();
257                List<ClassDoc> subs = classtree.subinterfaces(cd);
258                if (subs != null) {
259                    ret.addAll(subs);
260                    for (Iterator<ClassDoc> it = subs.iterator(); it.hasNext();) {
261                        ret.addAll(subinterfaces(it.next()));
262                    }
263                }
264                addAll(classToSubinterface, cd, ret);
265            }
266            return ret;
267        }
268    
269        /**
270         * Return all implementing classes of an interface (including
271         * all subclasses of implementing classes and all classes
272         * implementing subinterfaces) AND fill-in both classToImplementingClass
273         * and classToSubinterface maps.
274         */
275        private Collection<ClassDoc> implementingClasses(ClassDoc cd) {
276            Collection<ClassDoc> ret = classToImplementingClass.get(cd.qualifiedName());
277            if (ret == null) {
278                ret = new TreeSet<ClassDoc>();
279                List<ClassDoc> impl = classtree.implementingclasses(cd);
280                if (impl != null) {
281                    ret.addAll(impl);
282                    for (Iterator<ClassDoc> it = impl.iterator(); it.hasNext();) {
283                        ret.addAll(subclasses(it.next()));
284                    }
285                }
286                for (Iterator<ClassDoc> it = subinterfaces(cd).iterator(); it.hasNext();) {
287                    ret.addAll(implementingClasses(it.next()));
288                }
289                addAll(classToImplementingClass, cd, ret);
290            }
291            return ret;
292        }
293    
294        /**
295         * Determine classes used by a method or constructor, so they can be
296         * inverse mapped.
297         */
298        private void mapExecutable(ExecutableMemberDoc em) {
299            Parameter[] params = em.parameters();
300            boolean isConstructor = em.isConstructor();
301            List<Type> classArgs = new ArrayList<Type>();
302            for (int k = 0; k < params.length; k++) {
303                Type pcd = params[k].type();
304                // primitives don't get mapped, also avoid dups
305                if ((! params[k].type().isPrimitive()) &&
306                     ! classArgs.contains(pcd) &&
307                     ! (pcd instanceof TypeVariable)) {
308                    add(isConstructor? classToConstructorArgs :classToMethodArgs,
309                            pcd.asClassDoc(), em);
310                    classArgs.add(pcd);
311                    mapTypeParameters(isConstructor?
312                       classToConstructorDocArgTypeParam : classToExecMemberDocArgTypeParam,
313                       pcd, em);
314                }
315                mapAnnotations(
316                    isConstructor ?
317                        classToConstructorParamAnnotation :
318                        classToExecMemberDocParamAnnotation,
319                    params[k], em);
320            }
321            ClassDoc[] thr = em.thrownExceptions();
322            for (int k = 0; k < thr.length; k++) {
323                add(isConstructor? classToConstructorThrows : classToMethodThrows,
324                        thr[k], em);
325            }
326        }
327    
328        private <T> List<T> refList(Map<String,List<T>> map, ClassDoc cd) {
329            List<T> list = map.get(cd.qualifiedName());
330            if (list == null) {
331                List<T> l = new ArrayList<T>();
332                list = l;
333                map.put(cd.qualifiedName(), list);
334            }
335            return list;
336        }
337    
338        private Set<PackageDoc> packageSet(ClassDoc cd) {
339            Set<PackageDoc> pkgSet = classToPackage.get(cd.qualifiedName());
340            if (pkgSet == null) {
341                pkgSet = new TreeSet<PackageDoc>();
342                classToPackage.put(cd.qualifiedName(), pkgSet);
343            }
344            return pkgSet;
345        }
346    
347        private Set<ClassDoc> classSet(ClassDoc cd) {
348            Set<ClassDoc> clsSet = classToClass.get(cd.qualifiedName());
349            if (clsSet == null) {
350                Set<ClassDoc> s = new TreeSet<ClassDoc>();
351                clsSet = s;
352                classToClass.put(cd.qualifiedName(), clsSet);
353            }
354            return clsSet;
355        }
356    
357        private <T extends ProgramElementDoc> void add(Map<String,List<T>> map, ClassDoc cd, T ref) {
358            // add to specified map
359            refList(map, cd).add(ref);
360    
361            // add ref's package to package map and class map
362            packageSet(cd).add(ref.containingPackage());
363    
364            classSet(cd).add(ref instanceof MemberDoc?
365                    ((MemberDoc)ref).containingClass() :
366                        (ClassDoc)ref);
367        }
368    
369        private void addAll(Map<String,List<ClassDoc>> map, ClassDoc cd, Collection<ClassDoc> refs) {
370            if (refs == null) {
371                return;
372            }
373            // add to specified map
374            refList(map, cd).addAll(refs);
375    
376            Set<PackageDoc> pkgSet = packageSet(cd);
377            Set<ClassDoc> clsSet = classSet(cd);
378            // add ref's package to package map and class map
379            for (Iterator<ClassDoc> it = refs.iterator(); it.hasNext();) {
380                ClassDoc cls = it.next();
381                pkgSet.add(cls.containingPackage());
382                clsSet.add(cls);
383    
384            }
385        }
386    
387        /**
388         * Map the ClassDocs to the ProgramElementDocs that use them as
389         * type parameters.
390         *
391         * @param map the map the insert the information into.
392         * @param doc the doc whose type parameters are being checked.
393         * @param holder the holder that owns the type parameters.
394         */
395        private <T extends ProgramElementDoc> void mapTypeParameters(Map<String,List<T>> map, Object doc,
396                T holder) {
397            TypeVariable[] typeVariables;
398            if (doc instanceof ClassDoc) {
399                typeVariables = ((ClassDoc) doc).typeParameters();
400            } else if (doc instanceof WildcardType) {
401                Type[] extendsBounds = ((WildcardType) doc).extendsBounds();
402                for (int k = 0; k < extendsBounds.length; k++) {
403                    addTypeParameterToMap(map, extendsBounds[k], holder);
404                }
405                Type[] superBounds = ((WildcardType) doc).superBounds();
406                for (int k = 0; k < superBounds.length; k++) {
407                    addTypeParameterToMap(map, superBounds[k], holder);
408                }
409                return;
410            } else if (doc instanceof ParameterizedType) {
411                Type[] typeArguments = ((ParameterizedType) doc).typeArguments();
412                for (int k = 0; k < typeArguments.length; k++) {
413                    addTypeParameterToMap(map, typeArguments[k], holder);
414                }
415                return;
416            } else if (doc instanceof ExecutableMemberDoc) {
417                typeVariables = ((ExecutableMemberDoc) doc).typeParameters();
418            } else if (doc instanceof FieldDoc) {
419                Type fieldType = ((FieldDoc) doc).type();
420                mapTypeParameters(map, fieldType, holder);
421                return;
422            } else {
423                return;
424            }
425            for (int i = 0; i < typeVariables.length; i++) {
426                Type[] bounds = typeVariables[i].bounds();
427                for (int j = 0; j < bounds.length; j++) {
428                    addTypeParameterToMap(map, bounds[j], holder);
429                }
430            }
431        }
432    
433        /**
434         * Map the AnnotationType to the ProgramElementDocs that use them as
435         * type parameters.
436         *
437         * @param map the map the insert the information into.
438         * @param doc the doc whose type parameters are being checked.
439         * @param holder the holder that owns the type parameters.
440         */
441        private <T extends ProgramElementDoc> void mapAnnotations(Map<String,List<T>> map, Object doc,
442                T holder) {
443            AnnotationDesc[] annotations;
444            boolean isPackage = false;
445            if (doc instanceof ProgramElementDoc) {
446                annotations = ((ProgramElementDoc) doc).annotations();
447            } else if (doc instanceof PackageDoc) {
448                annotations = ((PackageDoc) doc).annotations();
449                isPackage = true;
450            } else if (doc instanceof Parameter) {
451                annotations = ((Parameter) doc).annotations();
452            } else {
453                throw new DocletAbortException();
454            }
455            for (int i = 0; i < annotations.length; i++) {
456                AnnotationTypeDoc annotationDoc = annotations[i].annotationType();
457                if (isPackage)
458                    refList(map, annotationDoc).add(holder);
459                else
460                    add(map, annotationDoc, holder);
461            }
462        }
463    
464    
465        /**
466         * Map the AnnotationType to the ProgramElementDocs that use them as
467         * type parameters.
468         *
469         * @param map the map the insert the information into.
470         * @param doc the doc whose type parameters are being checked.
471         * @param holder the holder that owns the type parameters.
472         */
473        private <T extends PackageDoc> void mapAnnotations(Map<String,List<T>> map, PackageDoc doc,
474                T holder) {
475            AnnotationDesc[] annotations;
476            annotations = doc.annotations();
477            for (int i = 0; i < annotations.length; i++) {
478                AnnotationTypeDoc annotationDoc = annotations[i].annotationType();
479                refList(map, annotationDoc).add(holder);
480            }
481        }
482    
483        private <T extends ProgramElementDoc> void addTypeParameterToMap(Map<String,List<T>> map, Type type,
484                T holder) {
485            if (type instanceof ClassDoc) {
486                add(map, (ClassDoc) type, holder);
487            } else if (type instanceof ParameterizedType) {
488                add(map, ((ParameterizedType) type).asClassDoc(), holder);
489            }
490            mapTypeParameters(map, type, holder);
491        }
492    }