src/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java

Mon, 02 May 2011 02:13:02 -0700

author
bpatel
date
Mon, 02 May 2011 02:13:02 -0700
changeset 995
62bc3775d5bb
parent 554
9d9f26857129
child 1357
c75be5bc5283
permissions
-rw-r--r--

6492694: @deprecated tag doesn't work in package-info files.
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.doclets.internal.toolkit.util;
    28 import com.sun.javadoc.*;
    29 import com.sun.tools.doclets.internal.toolkit.*;
    30 import java.util.*;
    32 /**
    33  * A data structure that encapsulates the visible members of a particular
    34  * type for a given class tree.  To use this data structor, you must specify
    35  * the type of member you are interested in (nested class, field, constructor
    36  * or method) and the leaf of the class tree.  The data structure will map
    37  * all visible members in the leaf and classes above the leaf in the tree.
    38  *
    39  * This code is not part of an API.
    40  * It is implementation that is subject to change.
    41  * Do not use it as an API
    42  *
    43  * @author Atul M Dambalkar
    44  * @author Jamie Ho (rewrite)
    45  */
    46 public class VisibleMemberMap {
    48     private boolean noVisibleMembers = true;
    50     public static final int INNERCLASSES    = 0;
    51     public static final int ENUM_CONSTANTS  = 1;
    52     public static final int FIELDS          = 2;
    53     public static final int CONSTRUCTORS    = 3;
    54     public static final int METHODS         = 4;
    55     public static final int ANNOTATION_TYPE_MEMBER_OPTIONAL = 5;
    56     public static final int ANNOTATION_TYPE_MEMBER_REQUIRED = 6;
    58     /**
    59      * The total number of member types is {@value}.
    60      */
    61     public static final int NUM_MEMBER_TYPES = 7;
    63     public static final String STARTLEVEL = "start";
    65     /**
    66      * List of ClassDoc objects for which ClassMembers objects are built.
    67      */
    68     private final List<ClassDoc> visibleClasses = new ArrayList<ClassDoc>();
    70     /**
    71      * Map for each member name on to a map which contains members with same
    72      * name-signature. The mapped map will contain mapping for each MemberDoc
    73      * onto it's respecive level string.
    74      */
    75     private final Map<Object,Map<ProgramElementDoc,String>> memberNameMap = new HashMap<Object,Map<ProgramElementDoc,String>>();
    77     /**
    78      * Map of class and it's ClassMembers object.
    79      */
    80     private final Map<ClassDoc,ClassMembers> classMap = new HashMap<ClassDoc,ClassMembers>();
    82     /**
    83      * Type whose visible members are requested.  This is the leaf of
    84      * the class tree being mapped.
    85      */
    86     private final ClassDoc classdoc;
    88     /**
    89      * Member kind: InnerClasses/Fields/Methods?
    90      */
    91     private final int kind;
    93     /**
    94      * Deprected members should be excluded or not?
    95      */
    96     private final boolean nodepr;
    98     /**
    99      * Construct a VisibleMemberMap of the given type for the given
   100      * class.  If nodepr is true, exclude the deprecated members from
   101      * the map.
   102      *
   103      * @param classdoc the class whose members are being mapped.
   104      * @param kind the kind of member that is being mapped.
   105      * @param nodepr if true, exclude the deprecated members from the map.
   106      */
   107     public VisibleMemberMap(ClassDoc classdoc, int kind, boolean nodepr) {
   108         this.classdoc = classdoc;
   109         this.nodepr = nodepr;
   110         this.kind = kind;
   111         new ClassMembers(classdoc, STARTLEVEL).build();
   112     }
   114     /**
   115      * Return the list of visible classes in this map.
   116      *
   117      * @return the list of visible classes in this map.
   118      */
   119     public List<ClassDoc> getVisibleClassesList() {
   120         sort(visibleClasses);
   121         return visibleClasses;
   122     }
   124     /**
   125      * Return the package private members inherited by the class.  Only return
   126      * if parent is package private and not documented.
   127      *
   128      * @param configuation the current configuration of the doclet.
   129      * @return the package private members inherited by the class.
   130      */
   131     private List<ProgramElementDoc> getInheritedPackagePrivateMethods(Configuration configuration) {
   132         List<ProgramElementDoc> results = new ArrayList<ProgramElementDoc>();
   133         for (Iterator<ClassDoc> iter = visibleClasses.iterator(); iter.hasNext(); ) {
   134             ClassDoc currentClass = iter.next();
   135             if (currentClass != classdoc &&
   136                 currentClass.isPackagePrivate() &&
   137                 !Util.isLinkable(currentClass, configuration)) {
   138                 // Document these members in the child class because
   139                 // the parent is inaccessible.
   140                 results.addAll(getMembersFor(currentClass));
   141             }
   142         }
   143         return results;
   144     }
   146     /**
   147      * Return the visible members of the class being mapped.  Also append at the
   148      * end of the list members that are inherited by inaccessible parents. We
   149      * document these members in the child because the parent is not documented.
   150      *
   151      * @param configuation the current configuration of the doclet.
   152      */
   153     public List<ProgramElementDoc> getLeafClassMembers(Configuration configuration) {
   154         List<ProgramElementDoc> result = getMembersFor(classdoc);
   155         result.addAll(getInheritedPackagePrivateMethods(configuration));
   156         return result;
   157     }
   159     /**
   160      * Retrn the list of members for the given class.
   161      *
   162      * @param cd the class to retrieve the list of visible members for.
   163      *
   164      * @return the list of members for the given class.
   165      */
   166     public List<ProgramElementDoc> getMembersFor(ClassDoc cd) {
   167         ClassMembers clmembers = classMap.get(cd);
   168         if (clmembers == null) {
   169             return new ArrayList<ProgramElementDoc>();
   170         }
   171         return clmembers.getMembers();
   172     }
   174     /**
   175      * Sort the given mixed list of classes and interfaces to a list of
   176      * classes followed by interfaces traversed. Don't sort alphabetically.
   177      */
   178     private void sort(List<ClassDoc> list) {
   179         List<ClassDoc> classes = new ArrayList<ClassDoc>();
   180         List<ClassDoc> interfaces = new ArrayList<ClassDoc>();
   181         for (int i = 0; i < list.size(); i++) {
   182             ClassDoc cd = list.get(i);
   183             if (cd.isClass()) {
   184                 classes.add(cd);
   185             } else {
   186                 interfaces.add(cd);
   187             }
   188         }
   189         list.clear();
   190         list.addAll(classes);
   191         list.addAll(interfaces);
   192     }
   194     private void fillMemberLevelMap(List<ProgramElementDoc> list, String level) {
   195         for (int i = 0; i < list.size(); i++) {
   196             Object key = getMemberKey(list.get(i));
   197             Map<ProgramElementDoc,String> memberLevelMap = memberNameMap.get(key);
   198             if (memberLevelMap == null) {
   199                 memberLevelMap = new HashMap<ProgramElementDoc,String>();
   200                 memberNameMap.put(key, memberLevelMap);
   201             }
   202             memberLevelMap.put(list.get(i), level);
   203         }
   204     }
   206     private void purgeMemberLevelMap(List<ProgramElementDoc> list, String level) {
   207         for (int i = 0; i < list.size(); i++) {
   208             Object key = getMemberKey(list.get(i));
   209             Map<ProgramElementDoc, String> memberLevelMap = memberNameMap.get(key);
   210             if (level.equals(memberLevelMap.get(list.get(i))))
   211                 memberLevelMap.remove(list.get(i));
   212         }
   213     }
   215     /**
   216      * Represents a class member.  We should be able to just use a
   217      * ProgramElementDoc instead of this class, but that doesn't take
   218      * type variables in consideration when comparing.
   219      */
   220     private class ClassMember {
   221         private Set<ProgramElementDoc> members;
   223         public ClassMember(ProgramElementDoc programElementDoc) {
   224             members = new HashSet<ProgramElementDoc>();
   225             members.add(programElementDoc);
   226         }
   228         public void addMember(ProgramElementDoc programElementDoc) {
   229             members.add(programElementDoc);
   230         }
   232         public boolean isEqual(MethodDoc member) {
   233             for (Iterator<ProgramElementDoc> iter = members.iterator(); iter.hasNext(); ) {
   234                 MethodDoc member2 = (MethodDoc) iter.next();
   235                 if (Util.executableMembersEqual(member, member2)) {
   236                     members.add(member);
   237                         return true;
   238                 }
   239             }
   240             return false;
   241         }
   242     }
   244     /**
   245      * A data structure that represents the class members for
   246      * a visible class.
   247      */
   248     private class ClassMembers {
   250         /**
   251          * The mapping class, whose inherited members are put in the
   252          * {@link #members} list.
   253          */
   254         private ClassDoc mappingClass;
   256         /**
   257          * List of inherited members from the mapping class.
   258          */
   259         private List<ProgramElementDoc> members = new ArrayList<ProgramElementDoc>();
   261         /**
   262          * Level/Depth of inheritance.
   263          */
   264         private String level;
   266         /**
   267          * Return list of inherited members from mapping class.
   268          *
   269          * @return List Inherited members.
   270          */
   271         public List<ProgramElementDoc> getMembers() {
   272             return members;
   273         }
   275         private ClassMembers(ClassDoc mappingClass, String level) {
   276             this.mappingClass = mappingClass;
   277             this.level = level;
   278             if (classMap.containsKey(mappingClass) &&
   279                         level.startsWith(classMap.get(mappingClass).level)) {
   280                 //Remove lower level class so that it can be replaced with
   281                 //same class found at higher level.
   282                 purgeMemberLevelMap(getClassMembers(mappingClass, false),
   283                     classMap.get(mappingClass).level);
   284                 classMap.remove(mappingClass);
   285                 visibleClasses.remove(mappingClass);
   286             }
   287             if (!classMap.containsKey(mappingClass)) {
   288                 classMap.put(mappingClass, this);
   289                 visibleClasses.add(mappingClass);
   290             }
   292         }
   294         private void build() {
   295             if (kind == CONSTRUCTORS) {
   296                 addMembers(mappingClass);
   297             } else {
   298                 mapClass();
   299             }
   300         }
   302         private void mapClass() {
   303             addMembers(mappingClass);
   304             ClassDoc[] interfaces = mappingClass.interfaces();
   305             for (int i = 0; i < interfaces.length; i++) {
   306                 String locallevel = level + 1;
   307                 ClassMembers cm = new ClassMembers(interfaces[i], locallevel);
   308                 cm.mapClass();
   309             }
   310             if (mappingClass.isClass()) {
   311                 ClassDoc superclass = mappingClass.superclass();
   312                 if (!(superclass == null || mappingClass.equals(superclass))) {
   313                     ClassMembers cm = new ClassMembers(superclass,
   314                                                        level + "c");
   315                     cm.mapClass();
   316                 }
   317             }
   318         }
   320         /**
   321          * Get all the valid members from the mapping class. Get the list of
   322          * members for the class to be included into(ctii), also get the level
   323          * string for ctii. If mapping class member is not already in the
   324          * inherited member list and if it is visible in the ctii and not
   325          * overridden, put such a member in the inherited member list.
   326          * Adjust member-level-map, class-map.
   327          */
   328         private void addMembers(ClassDoc fromClass) {
   329             List<ProgramElementDoc> cdmembers = getClassMembers(fromClass, true);
   330             List<ProgramElementDoc> incllist = new ArrayList<ProgramElementDoc>();
   331             for (int i = 0; i < cdmembers.size(); i++) {
   332                 ProgramElementDoc pgmelem = cdmembers.get(i);
   333                 if (!found(members, pgmelem) &&
   334                     memberIsVisible(pgmelem) &&
   335                     !isOverridden(pgmelem, level)) {
   336                     incllist.add(pgmelem);
   337                 }
   338             }
   339             if (incllist.size() > 0) {
   340                 noVisibleMembers = false;
   341             }
   342             members.addAll(incllist);
   343             fillMemberLevelMap(getClassMembers(fromClass, false), level);
   344         }
   346         /**
   347          * Is given doc item visible in given classdoc in terms fo inheritance?
   348          * The given doc item is visible in the given classdoc if it is public
   349          * or protected and if it is package-private if it's containing class
   350          * is in the same package as the given classdoc.
   351          */
   352         private boolean memberIsVisible(ProgramElementDoc pgmdoc) {
   353             if (pgmdoc.containingClass().equals(classdoc)) {
   354                 //Member is in class that we are finding visible members for.
   355                 //Of course it is visible.
   356                 return true;
   357             } else if (pgmdoc.isPrivate()) {
   358                 //Member is in super class or implemented interface.
   359                 //Private, so not inherited.
   360                 return false;
   361             } else if (pgmdoc.isPackagePrivate()) {
   362                 //Member is package private.  Only return true if its class is in
   363                 //same package.
   364                 return pgmdoc.containingClass().containingPackage().equals(
   365                     classdoc.containingPackage());
   366             } else {
   367                 //Public members are always inherited.
   368                 return true;
   369             }
   370         }
   372         /**
   373          * Return all available class members.
   374          */
   375         private List<ProgramElementDoc> getClassMembers(ClassDoc cd, boolean filter) {
   376             if (cd.isEnum() && kind == CONSTRUCTORS) {
   377                 //If any of these rules are hit, return empty array because
   378                 //we don't document these members ever.
   379                 return Arrays.asList(new ProgramElementDoc[] {});
   380             }
   381             ProgramElementDoc[] members = null;
   382             switch (kind) {
   383                 case ANNOTATION_TYPE_MEMBER_OPTIONAL:
   384                     members = cd.isAnnotationType() ?
   385                         filter((AnnotationTypeDoc) cd, false) :
   386                         new AnnotationTypeElementDoc[] {};
   387                     break;
   388                 case ANNOTATION_TYPE_MEMBER_REQUIRED:
   389                     members = cd.isAnnotationType() ?
   390                         filter((AnnotationTypeDoc) cd, true) :
   391                         new AnnotationTypeElementDoc[] {};
   392                     break;
   393                 case INNERCLASSES:
   394                     members = cd.innerClasses(filter);
   395                     break;
   396                 case ENUM_CONSTANTS:
   397                     members = cd.enumConstants();
   398                     break;
   399                 case FIELDS:
   400                     members = cd.fields(filter);
   401                     break;
   402                 case CONSTRUCTORS:
   403                     members = cd.constructors();
   404                     break;
   405                 case METHODS:
   406                     members = cd.methods(filter);
   407                     break;
   408                 default:
   409                     members = new ProgramElementDoc[0];
   410             }
   411             if (nodepr) {
   412                 return Util.excludeDeprecatedMembersAsList(members);
   413             }
   414             return Arrays.asList(members);
   415         }
   417         /**
   418          * Filter the annotation type members and return either the required
   419          * members or the optional members, depending on the value of the
   420          * required parameter.
   421          *
   422          * @param doc The annotation type to process.
   423          * @param required
   424          * @return the annotation type members and return either the required
   425          * members or the optional members, depending on the value of the
   426          * required parameter.
   427          */
   428         private AnnotationTypeElementDoc[] filter(AnnotationTypeDoc doc,
   429             boolean required) {
   430             AnnotationTypeElementDoc[] members = doc.elements();
   431             List<AnnotationTypeElementDoc> targetMembers = new ArrayList<AnnotationTypeElementDoc>();
   432             for (int i = 0; i < members.length; i++) {
   433                 if ((required && members[i].defaultValue() == null) ||
   434                      ((!required) && members[i].defaultValue() != null)){
   435                     targetMembers.add(members[i]);
   436                 }
   437             }
   438             return targetMembers.toArray(new AnnotationTypeElementDoc[]{});
   439         }
   441         private boolean found(List<ProgramElementDoc> list, ProgramElementDoc elem) {
   442             for (int i = 0; i < list.size(); i++) {
   443                 ProgramElementDoc pgmelem = list.get(i);
   444                 if (Util.matches(pgmelem, elem)) {
   445                     return true;
   446                 }
   447             }
   448             return false;
   449         }
   452         /**
   453          * Is member overridden? The member is overridden if it is found in the
   454          * same level hierarchy e.g. member at level "11" overrides member at
   455          * level "111".
   456          */
   457         private boolean isOverridden(ProgramElementDoc pgmdoc, String level) {
   458             Map<?,String> memberLevelMap = (Map<?,String>) memberNameMap.get(getMemberKey(pgmdoc));
   459             if (memberLevelMap == null)
   460                 return false;
   461             String mappedlevel = null;
   462             Iterator<String> iterator = memberLevelMap.values().iterator();
   463             while (iterator.hasNext()) {
   464                 mappedlevel = iterator.next();
   465                 if (mappedlevel.equals(STARTLEVEL) ||
   466                     (level.startsWith(mappedlevel) &&
   467                      !level.equals(mappedlevel))) {
   468                     return true;
   469                 }
   470             }
   471             return false;
   472         }
   473     }
   475     /**
   476      * Return true if this map has no visible members.
   477      *
   478      * @return true if this map has no visible members.
   479      */
   480     public boolean noVisibleMembers() {
   481         return noVisibleMembers;
   482     }
   484     private ClassMember getClassMember(MethodDoc member) {
   485         for (Iterator<?> iter = memberNameMap.keySet().iterator(); iter.hasNext();) {
   486             Object key = iter.next();
   487             if (key instanceof String) {
   488                 continue;
   489             } else if (((ClassMember) key).isEqual(member)) {
   490                 return (ClassMember) key;
   491             }
   492         }
   493         return new ClassMember(member);
   494     }
   496     /**
   497      * Return the key to the member map for the given member.
   498      */
   499     private Object getMemberKey(ProgramElementDoc doc) {
   500         if (doc.isConstructor()) {
   501             return doc.name() + ((ExecutableMemberDoc)doc).signature();
   502         } else if (doc.isMethod()) {
   503             return getClassMember((MethodDoc) doc);
   504         } else if (doc.isField() || doc.isEnumConstant() || doc.isAnnotationTypeElement()) {
   505             return doc.name();
   506         } else { // it's a class or interface
   507             String classOrIntName = doc.name();
   508             //Strip off the containing class name because we only want the member name.
   509             classOrIntName = classOrIntName.indexOf('.') != 0 ? classOrIntName.substring(classOrIntName.lastIndexOf('.'), classOrIntName.length()) : classOrIntName;
   510             return "clint" + classOrIntName;
   511         }
   512     }
   513 }

mercurial