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

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

mercurial