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

Thu, 24 May 2018 16:48:51 +0800

author
aoqi
date
Thu, 24 May 2018 16:48:51 +0800
changeset 3295
859dc787b52b
parent 3006
9731ab1f18ee
parent 2525
2eb010b6cb22
child 3719
9a2d9c6eca1d
permissions
-rw-r--r--

Merge

     1 /*
     2  * Copyright (c) 1999, 2016, 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 java.util.*;
    29 import java.util.regex.Pattern;
    31 import com.sun.javadoc.*;
    32 import com.sun.tools.doclets.internal.toolkit.*;
    34 /**
    35  * A data structure that encapsulates the visible members of a particular
    36  * type for a given class tree.  To use this data structor, you must specify
    37  * the type of member you are interested in (nested class, field, constructor
    38  * or method) and the leaf of the class tree.  The data structure will map
    39  * all visible members in the leaf and classes above the leaf in the tree.
    40  *
    41  *  <p><b>This is NOT part of any supported API.
    42  *  If you write code that depends on this, you do so at your own risk.
    43  *  This code and its internal interfaces are subject to change or
    44  *  deletion without notice.</b>
    45  *
    46  * @author Atul M Dambalkar
    47  * @author Jamie Ho (rewrite)
    48  */
    49 public class VisibleMemberMap {
    51     private boolean noVisibleMembers = true;
    53     public static final int INNERCLASSES    = 0;
    54     public static final int ENUM_CONSTANTS  = 1;
    55     public static final int FIELDS          = 2;
    56     public static final int CONSTRUCTORS    = 3;
    57     public static final int METHODS         = 4;
    58     public static final int ANNOTATION_TYPE_FIELDS = 5;
    59     public static final int ANNOTATION_TYPE_MEMBER_OPTIONAL = 6;
    60     public static final int ANNOTATION_TYPE_MEMBER_REQUIRED = 7;
    61     public static final int PROPERTIES      = 8;
    63     /**
    64      * The total number of member types is {@value}.
    65      */
    66     public static final int NUM_MEMBER_TYPES = 9;
    68     public static final String STARTLEVEL = "start";
    70     /**
    71      * List of ClassDoc objects for which ClassMembers objects are built.
    72      */
    73     private final List<ClassDoc> visibleClasses = new ArrayList<ClassDoc>();
    75     /**
    76      * Map for each member name on to a map which contains members with same
    77      * name-signature. The mapped map will contain mapping for each MemberDoc
    78      * onto it's respecive level string.
    79      */
    80     private final Map<Object,Map<ProgramElementDoc,String>> memberNameMap = new HashMap<Object,Map<ProgramElementDoc,String>>();
    82     /**
    83      * Map of class and it's ClassMembers object.
    84      */
    85     private final Map<ClassDoc,ClassMembers> classMap = new HashMap<ClassDoc,ClassMembers>();
    87     /**
    88      * Type whose visible members are requested.  This is the leaf of
    89      * the class tree being mapped.
    90      */
    91     private final ClassDoc classdoc;
    93     /**
    94      * Member kind: InnerClasses/Fields/Methods?
    95      */
    96     private final int kind;
    98     /**
    99      * The configuration this VisibleMemberMap was created with.
   100      */
   101     private final Configuration configuration;
   103     private static final Map<ClassDoc, ProgramElementDoc[]> propertiesCache =
   104             new HashMap<ClassDoc, ProgramElementDoc[]>();
   105     private static final Map<ProgramElementDoc, ProgramElementDoc> classPropertiesMap =
   106             new HashMap<ProgramElementDoc, ProgramElementDoc>();
   107     private static final Map<ProgramElementDoc, GetterSetter> getterSetterMap =
   108             new HashMap<ProgramElementDoc, GetterSetter>();
   110     /**
   111      * Construct a VisibleMemberMap of the given type for the given
   112      * class.
   113      *
   114      * @param classdoc the class whose members are being mapped.
   115      * @param kind the kind of member that is being mapped.
   116      * @param configuration the configuration to use to construct this
   117      * VisibleMemberMap. If the field configuration.nodeprecated is true the
   118      * deprecated members are excluded from the map. If the field
   119      * configuration.javafx is true the JavaFX features are used.
   120      */
   121     public VisibleMemberMap(ClassDoc classdoc,
   122                             int kind,
   123                             Configuration configuration) {
   124         this.classdoc = classdoc;
   125         this.kind = kind;
   126         this.configuration = configuration;
   127         new ClassMembers(classdoc, STARTLEVEL).build();
   128     }
   130     /**
   131      * Return the list of visible classes in this map.
   132      *
   133      * @return the list of visible classes in this map.
   134      */
   135     public List<ClassDoc> getVisibleClassesList() {
   136         sort(visibleClasses);
   137         return visibleClasses;
   138     }
   140     /**
   141      * Returns the property field documentation belonging to the given member.
   142      * @param ped the member for which the property documentation is needed.
   143      * @return the property field documentation, null if there is none.
   144      */
   145     public ProgramElementDoc getPropertyMemberDoc(ProgramElementDoc ped) {
   146         return classPropertiesMap.get(ped);
   147     }
   149     /**
   150      * Returns the getter documentation belonging to the given property method.
   151      * @param propertyMethod the method for which the getter is needed.
   152      * @return the getter documentation, null if there is none.
   153      */
   154     public ProgramElementDoc getGetterForProperty(ProgramElementDoc propertyMethod) {
   155         return getterSetterMap.get(propertyMethod).getGetter();
   156     }
   158     /**
   159      * Returns the setter documentation belonging to the given property method.
   160      * @param propertyMethod the method for which the setter is needed.
   161      * @return the setter documentation, null if there is none.
   162      */
   163     public ProgramElementDoc getSetterForProperty(ProgramElementDoc propertyMethod) {
   164         return getterSetterMap.get(propertyMethod).getSetter();
   165     }
   167     /**
   168      * Return the package private members inherited by the class.  Only return
   169      * if parent is package private and not documented.
   170      *
   171      * @param configuration the current configuration of the doclet.
   172      * @return the package private members inherited by the class.
   173      */
   174     private List<ProgramElementDoc> getInheritedPackagePrivateMethods(Configuration configuration) {
   175         List<ProgramElementDoc> results = new ArrayList<ProgramElementDoc>();
   176         for (Iterator<ClassDoc> iter = visibleClasses.iterator(); iter.hasNext(); ) {
   177             ClassDoc currentClass = iter.next();
   178             if (currentClass != classdoc &&
   179                 currentClass.isPackagePrivate() &&
   180                 !Util.isLinkable(currentClass, configuration)) {
   181                 // Document these members in the child class because
   182                 // the parent is inaccessible.
   183                 results.addAll(getMembersFor(currentClass));
   184             }
   185         }
   186         return results;
   187     }
   189     /**
   190      * Return the visible members of the class being mapped.  Also append at the
   191      * end of the list members that are inherited by inaccessible parents. We
   192      * document these members in the child because the parent is not documented.
   193      *
   194      * @param configuration the current configuration of the doclet.
   195      */
   196     public List<ProgramElementDoc> getLeafClassMembers(Configuration configuration) {
   197         List<ProgramElementDoc> result = getMembersFor(classdoc);
   198         result.addAll(getInheritedPackagePrivateMethods(configuration));
   199         return result;
   200     }
   202     /**
   203      * Retrn the list of members for the given class.
   204      *
   205      * @param cd the class to retrieve the list of visible members for.
   206      *
   207      * @return the list of members for the given class.
   208      */
   209     public List<ProgramElementDoc> getMembersFor(ClassDoc cd) {
   210         ClassMembers clmembers = classMap.get(cd);
   211         if (clmembers == null) {
   212             return new ArrayList<ProgramElementDoc>();
   213         }
   214         return clmembers.getMembers();
   215     }
   217     /**
   218      * Sort the given mixed list of classes and interfaces to a list of
   219      * classes followed by interfaces traversed. Don't sort alphabetically.
   220      */
   221     private void sort(List<ClassDoc> list) {
   222         List<ClassDoc> classes = new ArrayList<ClassDoc>();
   223         List<ClassDoc> interfaces = new ArrayList<ClassDoc>();
   224         for (int i = 0; i < list.size(); i++) {
   225             ClassDoc cd = list.get(i);
   226             if (cd.isClass()) {
   227                 classes.add(cd);
   228             } else {
   229                 interfaces.add(cd);
   230             }
   231         }
   232         list.clear();
   233         list.addAll(classes);
   234         list.addAll(interfaces);
   235     }
   237     private void fillMemberLevelMap(List<ProgramElementDoc> list, String level) {
   238         for (int i = 0; i < list.size(); i++) {
   239             Object key = getMemberKey(list.get(i));
   240             Map<ProgramElementDoc,String> memberLevelMap = memberNameMap.get(key);
   241             if (memberLevelMap == null) {
   242                 memberLevelMap = new HashMap<ProgramElementDoc,String>();
   243                 memberNameMap.put(key, memberLevelMap);
   244             }
   245             memberLevelMap.put(list.get(i), level);
   246         }
   247     }
   249     private void purgeMemberLevelMap(List<ProgramElementDoc> list, String level) {
   250         for (int i = 0; i < list.size(); i++) {
   251             Object key = getMemberKey(list.get(i));
   252             Map<ProgramElementDoc, String> memberLevelMap = memberNameMap.get(key);
   253             if (memberLevelMap != null && level.equals(memberLevelMap.get(list.get(i))))
   254                 memberLevelMap.remove(list.get(i));
   255         }
   256     }
   258     /**
   259      * Represents a class member.  We should be able to just use a
   260      * ProgramElementDoc instead of this class, but that doesn't take
   261      * type variables in consideration when comparing.
   262      */
   263     private class ClassMember {
   264         private Set<ProgramElementDoc> members;
   266         public ClassMember(ProgramElementDoc programElementDoc) {
   267             members = new HashSet<ProgramElementDoc>();
   268             members.add(programElementDoc);
   269         }
   271         public void addMember(ProgramElementDoc programElementDoc) {
   272             members.add(programElementDoc);
   273         }
   275         public boolean isEqual(MethodDoc member) {
   276             for (Iterator<ProgramElementDoc> iter = members.iterator(); iter.hasNext(); ) {
   277                 MethodDoc member2 = (MethodDoc) iter.next();
   278                 if (Util.executableMembersEqual(member, member2)) {
   279                     members.add(member);
   280                         return true;
   281                 }
   282             }
   283             return false;
   284         }
   285     }
   287     /**
   288      * A data structure that represents the class members for
   289      * a visible class.
   290      */
   291     private class ClassMembers {
   293         /**
   294          * The mapping class, whose inherited members are put in the
   295          * {@link #members} list.
   296          */
   297         private ClassDoc mappingClass;
   299         /**
   300          * List of inherited members from the mapping class.
   301          */
   302         private List<ProgramElementDoc> members = new ArrayList<ProgramElementDoc>();
   304         /**
   305          * Level/Depth of inheritance.
   306          */
   307         private String level;
   309         /**
   310          * Return list of inherited members from mapping class.
   311          *
   312          * @return List Inherited members.
   313          */
   314         public List<ProgramElementDoc> getMembers() {
   315             return members;
   316         }
   318         private ClassMembers(ClassDoc mappingClass, String level) {
   319             this.mappingClass = mappingClass;
   320             this.level = level;
   321             if (classMap.containsKey(mappingClass) &&
   322                         level.startsWith(classMap.get(mappingClass).level)) {
   323                 //Remove lower level class so that it can be replaced with
   324                 //same class found at higher level.
   325                 purgeMemberLevelMap(getClassMembers(mappingClass, false),
   326                     classMap.get(mappingClass).level);
   327                 classMap.remove(mappingClass);
   328                 visibleClasses.remove(mappingClass);
   329             }
   330             if (!classMap.containsKey(mappingClass)) {
   331                 classMap.put(mappingClass, this);
   332                 visibleClasses.add(mappingClass);
   333             }
   335         }
   337         private void build() {
   338             if (kind == CONSTRUCTORS) {
   339                 addMembers(mappingClass);
   340             } else {
   341                 mapClass();
   342             }
   343         }
   345         private void mapClass() {
   346             addMembers(mappingClass);
   347             ClassDoc[] interfaces = mappingClass.interfaces();
   348             for (int i = 0; i < interfaces.length; i++) {
   349                 String locallevel = level + 1;
   350                 ClassMembers cm = new ClassMembers(interfaces[i], locallevel);
   351                 cm.mapClass();
   352             }
   353             if (mappingClass.isClass()) {
   354                 ClassDoc superclass = mappingClass.superclass();
   355                 if (!(superclass == null || mappingClass.equals(superclass))) {
   356                     ClassMembers cm = new ClassMembers(superclass,
   357                                                        level + "c");
   358                     cm.mapClass();
   359                 }
   360             }
   361         }
   363         /**
   364          * Get all the valid members from the mapping class. Get the list of
   365          * members for the class to be included into(ctii), also get the level
   366          * string for ctii. If mapping class member is not already in the
   367          * inherited member list and if it is visible in the ctii and not
   368          * overridden, put such a member in the inherited member list.
   369          * Adjust member-level-map, class-map.
   370          */
   371         private void addMembers(ClassDoc fromClass) {
   372             List<ProgramElementDoc> cdmembers = getClassMembers(fromClass, true);
   373             List<ProgramElementDoc> incllist = new ArrayList<ProgramElementDoc>();
   374             for (int i = 0; i < cdmembers.size(); i++) {
   375                 ProgramElementDoc pgmelem = cdmembers.get(i);
   376                 if (!found(members, pgmelem) &&
   377                     memberIsVisible(pgmelem) &&
   378                     !isOverridden(pgmelem, level) &&
   379                     !isTreatedAsPrivate(pgmelem)) {
   380                         incllist.add(pgmelem);
   381                 }
   382             }
   383             if (incllist.size() > 0) {
   384                 noVisibleMembers = false;
   385             }
   386             members.addAll(incllist);
   387             fillMemberLevelMap(getClassMembers(fromClass, false), level);
   388         }
   390         private boolean isTreatedAsPrivate(ProgramElementDoc pgmelem) {
   391             if (!configuration.javafx) {
   392                 return false;
   393             }
   395             Tag[] aspTags = pgmelem.tags("@treatAsPrivate");
   396             boolean result = (aspTags != null) && (aspTags.length > 0);
   397             return result;
   398         }
   400         /**
   401          * Is given doc item visible in given classdoc in terms fo inheritance?
   402          * The given doc item is visible in the given classdoc if it is public
   403          * or protected and if it is package-private if it's containing class
   404          * is in the same package as the given classdoc.
   405          */
   406         private boolean memberIsVisible(ProgramElementDoc pgmdoc) {
   407             if (pgmdoc.containingClass().equals(classdoc)) {
   408                 //Member is in class that we are finding visible members for.
   409                 //Of course it is visible.
   410                 return true;
   411             } else if (pgmdoc.isPrivate()) {
   412                 //Member is in super class or implemented interface.
   413                 //Private, so not inherited.
   414                 return false;
   415             } else if (pgmdoc.isPackagePrivate()) {
   416                 //Member is package private.  Only return true if its class is in
   417                 //same package.
   418                 return pgmdoc.containingClass().containingPackage().equals(
   419                     classdoc.containingPackage());
   420             } else {
   421                 //Public members are always inherited.
   422                 return true;
   423             }
   424         }
   426         /**
   427          * Return all available class members.
   428          */
   429         private List<ProgramElementDoc> getClassMembers(ClassDoc cd, boolean filter) {
   430             if (cd.isEnum() && kind == CONSTRUCTORS) {
   431                 //If any of these rules are hit, return empty array because
   432                 //we don't document these members ever.
   433                 return Arrays.asList(new ProgramElementDoc[] {});
   434             }
   435             ProgramElementDoc[] members = null;
   436             switch (kind) {
   437                 case ANNOTATION_TYPE_FIELDS:
   438                     members = cd.fields(filter);
   439                     break;
   440                 case ANNOTATION_TYPE_MEMBER_OPTIONAL:
   441                     members = cd.isAnnotationType() ?
   442                         filter((AnnotationTypeDoc) cd, false) :
   443                         new AnnotationTypeElementDoc[] {};
   444                     break;
   445                 case ANNOTATION_TYPE_MEMBER_REQUIRED:
   446                     members = cd.isAnnotationType() ?
   447                         filter((AnnotationTypeDoc) cd, true) :
   448                         new AnnotationTypeElementDoc[] {};
   449                     break;
   450                 case INNERCLASSES:
   451                     members = cd.innerClasses(filter);
   452                     break;
   453                 case ENUM_CONSTANTS:
   454                     members = cd.enumConstants();
   455                     break;
   456                 case FIELDS:
   457                     members = cd.fields(filter);
   458                     break;
   459                 case CONSTRUCTORS:
   460                     members = cd.constructors();
   461                     break;
   462                 case METHODS:
   463                     members = cd.methods(filter);
   464                     checkOnPropertiesTags((MethodDoc[])members);
   465                     break;
   466                 case PROPERTIES:
   467                     members = properties(cd, filter);
   468                     break;
   469                 default:
   470                     members = new ProgramElementDoc[0];
   471             }
   472             // Deprected members should be excluded or not?
   473             if (configuration.nodeprecated) {
   474                 return Util.excludeDeprecatedMembersAsList(members);
   475             }
   476             return Arrays.asList(members);
   477         }
   479         /**
   480          * Filter the annotation type members and return either the required
   481          * members or the optional members, depending on the value of the
   482          * required parameter.
   483          *
   484          * @param doc The annotation type to process.
   485          * @param required
   486          * @return the annotation type members and return either the required
   487          * members or the optional members, depending on the value of the
   488          * required parameter.
   489          */
   490         private AnnotationTypeElementDoc[] filter(AnnotationTypeDoc doc,
   491             boolean required) {
   492             AnnotationTypeElementDoc[] members = doc.elements();
   493             List<AnnotationTypeElementDoc> targetMembers = new ArrayList<AnnotationTypeElementDoc>();
   494             for (int i = 0; i < members.length; i++) {
   495                 if ((required && members[i].defaultValue() == null) ||
   496                      ((!required) && members[i].defaultValue() != null)){
   497                     targetMembers.add(members[i]);
   498                 }
   499             }
   500             return targetMembers.toArray(new AnnotationTypeElementDoc[]{});
   501         }
   503         private boolean found(List<ProgramElementDoc> list, ProgramElementDoc elem) {
   504             for (int i = 0; i < list.size(); i++) {
   505                 ProgramElementDoc pgmelem = list.get(i);
   506                 if (Util.matches(pgmelem, elem)) {
   507                     return true;
   508                 }
   509             }
   510             return false;
   511         }
   514         /**
   515          * Is member overridden? The member is overridden if it is found in the
   516          * same level hierarchy e.g. member at level "11" overrides member at
   517          * level "111".
   518          */
   519         private boolean isOverridden(ProgramElementDoc pgmdoc, String level) {
   520             Map<?,String> memberLevelMap = (Map<?,String>) memberNameMap.get(getMemberKey(pgmdoc));
   521             if (memberLevelMap == null)
   522                 return false;
   523             String mappedlevel = null;
   524             Iterator<String> iterator = memberLevelMap.values().iterator();
   525             while (iterator.hasNext()) {
   526                 mappedlevel = iterator.next();
   527                 if (mappedlevel.equals(STARTLEVEL) ||
   528                     (level.startsWith(mappedlevel) &&
   529                      !level.equals(mappedlevel))) {
   530                     return true;
   531                 }
   532             }
   533             return false;
   534         }
   536         private ProgramElementDoc[] properties(final ClassDoc cd, final boolean filter) {
   537             final MethodDoc[] allMethods = cd.methods(filter);
   538             final FieldDoc[] allFields = cd.fields(false);
   540             if (propertiesCache.containsKey(cd)) {
   541                 return propertiesCache.get(cd);
   542             }
   544             final List<MethodDoc> result = new ArrayList<MethodDoc>();
   546             for (final MethodDoc propertyMethod : allMethods) {
   548                 if (!isPropertyMethod(propertyMethod)) {
   549                     continue;
   550                 }
   552                 final MethodDoc getter = getterForField(allMethods, propertyMethod);
   553                 final MethodDoc setter = setterForField(allMethods, propertyMethod);
   554                 final FieldDoc field = fieldForProperty(allFields, propertyMethod);
   556                 addToPropertiesMap(setter, getter, propertyMethod, field);
   557                 getterSetterMap.put(propertyMethod, new GetterSetter(getter, setter));
   558                 result.add(propertyMethod);
   559             }
   560             final ProgramElementDoc[] resultAray =
   561                     result.toArray(new ProgramElementDoc[result.size()]);
   562             propertiesCache.put(cd, resultAray);
   563             return resultAray;
   564         }
   566         private void addToPropertiesMap(MethodDoc setter,
   567                                         MethodDoc getter,
   568                                         MethodDoc propertyMethod,
   569                                         FieldDoc field) {
   570             if ((field == null)
   571                     || (field.getRawCommentText() == null)
   572                     || field.getRawCommentText().length() == 0) {
   573                 addToPropertiesMap(setter, propertyMethod);
   574                 addToPropertiesMap(getter, propertyMethod);
   575                 addToPropertiesMap(propertyMethod, propertyMethod);
   576             } else {
   577                 addToPropertiesMap(getter, field);
   578                 addToPropertiesMap(setter, field);
   579                 addToPropertiesMap(propertyMethod, field);
   580             }
   581         }
   583         private void addToPropertiesMap(ProgramElementDoc propertyMethod,
   584                                         ProgramElementDoc commentSource) {
   585             if (null == propertyMethod || null == commentSource) {
   586                 return;
   587             }
   588             final String methodRawCommentText = propertyMethod.getRawCommentText();
   590             /* The second condition is required for the property buckets. In
   591              * this case the comment is at the property method (not at the field)
   592              * and it needs to be listed in the map.
   593              */
   594             if ((null == methodRawCommentText || 0 == methodRawCommentText.length())
   595                     || propertyMethod.equals(commentSource)) {
   596                 classPropertiesMap.put(propertyMethod, commentSource);
   597             }
   598         }
   600         private MethodDoc getterForField(MethodDoc[] methods,
   601                                          MethodDoc propertyMethod) {
   602             final String propertyMethodName = propertyMethod.name();
   603             final String fieldName =
   604                     propertyMethodName.substring(0,
   605                             propertyMethodName.lastIndexOf("Property"));
   606             final String fieldNameUppercased =
   607                     "" + Character.toUpperCase(fieldName.charAt(0))
   608                                             + fieldName.substring(1);
   609             final String getterNamePattern;
   610             final String fieldTypeName = propertyMethod.returnType().toString();
   611             if ("boolean".equals(fieldTypeName)
   612                     || fieldTypeName.endsWith("BooleanProperty")) {
   613                 getterNamePattern = "(is|get)" + fieldNameUppercased;
   614             } else {
   615                 getterNamePattern = "get" + fieldNameUppercased;
   616             }
   618             for (MethodDoc methodDoc : methods) {
   619                 if (Pattern.matches(getterNamePattern, methodDoc.name())) {
   620                     if (0 == methodDoc.parameters().length
   621                             && (methodDoc.isPublic() || methodDoc.isProtected())) {
   622                         return methodDoc;
   623                     }
   624                 }
   625             }
   626             return null;
   627         }
   629         private MethodDoc setterForField(MethodDoc[] methods,
   630                                          MethodDoc propertyMethod) {
   631             final String propertyMethodName = propertyMethod.name();
   632             final String fieldName =
   633                     propertyMethodName.substring(0,
   634                             propertyMethodName.lastIndexOf("Property"));
   635             final String fieldNameUppercased =
   636                     "" + Character.toUpperCase(fieldName.charAt(0))
   637                                              + fieldName.substring(1);
   638             final String setter = "set" + fieldNameUppercased;
   640             for (MethodDoc methodDoc : methods) {
   641                 if (setter.equals(methodDoc.name())) {
   642                     if (1 == methodDoc.parameters().length
   643                             && "void".equals(methodDoc.returnType().simpleTypeName())
   644                             && (methodDoc.isPublic() || methodDoc.isProtected())) {
   645                         return methodDoc;
   646                     }
   647                 }
   648             }
   649             return null;
   650         }
   652         private FieldDoc fieldForProperty(FieldDoc[] fields, MethodDoc property) {
   654             for (FieldDoc field : fields) {
   655                 final String fieldName = field.name();
   656                 final String propertyName = fieldName + "Property";
   657                 if (propertyName.equals(property.name())) {
   658                     return field;
   659                 }
   660             }
   661             return null;
   662         }
   664         // properties aren't named setA* or getA*
   665         private final Pattern pattern = Pattern.compile("[sg]et\\p{Upper}.*");
   666         private boolean isPropertyMethod(MethodDoc method) {
   667             if (!method.name().endsWith("Property")) {
   668                 return false;
   669             }
   671             if (! memberIsVisible(method)) {
   672                 return false;
   673             }
   675             if (pattern.matcher(method.name()).matches()) {
   676                 return false;
   677             }
   679             return 0 == method.parameters().length
   680                     && !"void".equals(method.returnType().simpleTypeName());
   681         }
   683         private void checkOnPropertiesTags(MethodDoc[] members) {
   684             for (MethodDoc methodDoc: members) {
   685                 if (methodDoc.isIncluded()) {
   686                     for (Tag tag: methodDoc.tags()) {
   687                         String tagName = tag.name();
   688                         if (tagName.equals("@propertySetter")
   689                                 || tagName.equals("@propertyGetter")
   690                                 || tagName.equals("@propertyDescription")) {
   691                             if (!isPropertyGetterOrSetter(members, methodDoc)) {
   692                                 configuration.message.warning(tag.position(),
   693                                         "doclet.javafx_tag_misuse");
   694                             }
   695                             break;
   696                         }
   697                     }
   698                 }
   699             }
   700         }
   702         private boolean isPropertyGetterOrSetter(MethodDoc[] members,
   703                                                  MethodDoc methodDoc) {
   704             boolean found = false;
   705             String propertyName = Util.propertyNameFromMethodName(configuration, methodDoc.name());
   706             if (!propertyName.isEmpty()) {
   707                 String propertyMethodName = propertyName + "Property";
   708                 for (MethodDoc member: members) {
   709                     if (member.name().equals(propertyMethodName)) {
   710                         found = true;
   711                         break;
   712                     }
   713                 }
   714             }
   715             return found;
   716         }
   717     }
   719     private class GetterSetter {
   720         private final ProgramElementDoc getter;
   721         private final ProgramElementDoc setter;
   723         public GetterSetter(ProgramElementDoc getter, ProgramElementDoc setter) {
   724             this.getter = getter;
   725             this.setter = setter;
   726         }
   728         public ProgramElementDoc getGetter() {
   729             return getter;
   730         }
   732         public ProgramElementDoc getSetter() {
   733             return setter;
   734         }
   735     }
   737     /**
   738      * Return true if this map has no visible members.
   739      *
   740      * @return true if this map has no visible members.
   741      */
   742     public boolean noVisibleMembers() {
   743         return noVisibleMembers;
   744     }
   746     private ClassMember getClassMember(MethodDoc member) {
   747         for (Iterator<?> iter = memberNameMap.keySet().iterator(); iter.hasNext();) {
   748             Object key = iter.next();
   749             if (key instanceof String) {
   750                 continue;
   751             } else if (((ClassMember) key).isEqual(member)) {
   752                 return (ClassMember) key;
   753             }
   754         }
   755         return new ClassMember(member);
   756     }
   758     /**
   759      * Return the key to the member map for the given member.
   760      */
   761     private Object getMemberKey(ProgramElementDoc doc) {
   762         if (doc.isConstructor()) {
   763             return doc.name() + ((ExecutableMemberDoc)doc).signature();
   764         } else if (doc.isMethod()) {
   765             return getClassMember((MethodDoc) doc);
   766         } else if (doc.isField() || doc.isEnumConstant() || doc.isAnnotationTypeElement()) {
   767             return doc.name();
   768         } else { // it's a class or interface
   769             String classOrIntName = doc.name();
   770             //Strip off the containing class name because we only want the member name.
   771             classOrIntName = classOrIntName.indexOf('.') != 0 ? classOrIntName.substring(classOrIntName.lastIndexOf('.'), classOrIntName.length()) : classOrIntName;
   772             return "clint" + classOrIntName;
   773         }
   774     }
   775 }

mercurial