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 */ 25 26 package com.sun.tools.doclets.internal.toolkit.util; 27 28 import java.util.*; 29 import java.util.regex.Pattern; 30 31 import com.sun.javadoc.*; 32 import com.sun.tools.doclets.internal.toolkit.*; 33 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 { 50 51 private boolean noVisibleMembers = true; 52 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; 62 63 /** 64 * The total number of member types is {@value}. 65 */ 66 public static final int NUM_MEMBER_TYPES = 9; 67 68 public static final String STARTLEVEL = "start"; 69 70 /** 71 * List of ClassDoc objects for which ClassMembers objects are built. 72 */ 73 private final List<ClassDoc> visibleClasses = new ArrayList<ClassDoc>(); 74 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>>(); 81 82 /** 83 * Map of class and it's ClassMembers object. 84 */ 85 private final Map<ClassDoc,ClassMembers> classMap = new HashMap<ClassDoc,ClassMembers>(); 86 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; 92 93 /** 94 * Member kind: InnerClasses/Fields/Methods? 95 */ 96 private final int kind; 97 98 /** 99 * The configuration this VisibleMemberMap was created with. 100 */ 101 private final Configuration configuration; 102 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>(); 109 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 } 129 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 } 139 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 } 148 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 } 157 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 } 166 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 } 188 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 } 201 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 } 216 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 } 236 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 } 248 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 } 257 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; 265 266 public ClassMember(ProgramElementDoc programElementDoc) { 267 members = new HashSet<ProgramElementDoc>(); 268 members.add(programElementDoc); 269 } 270 271 public void addMember(ProgramElementDoc programElementDoc) { 272 members.add(programElementDoc); 273 } 274 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 } 286 287 /** 288 * A data structure that represents the class members for 289 * a visible class. 290 */ 291 private class ClassMembers { 292 293 /** 294 * The mapping class, whose inherited members are put in the 295 * {@link #members} list. 296 */ 297 private ClassDoc mappingClass; 298 299 /** 300 * List of inherited members from the mapping class. 301 */ 302 private List<ProgramElementDoc> members = new ArrayList<ProgramElementDoc>(); 303 304 /** 305 * Level/Depth of inheritance. 306 */ 307 private String level; 308 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 } 317 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 } 334 335 } 336 337 private void build() { 338 if (kind == CONSTRUCTORS) { 339 addMembers(mappingClass); 340 } else { 341 mapClass(); 342 } 343 } 344 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 } 362 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 } 389 390 private boolean isTreatedAsPrivate(ProgramElementDoc pgmelem) { 391 if (!configuration.javafx) { 392 return false; 393 } 394 395 Tag[] aspTags = pgmelem.tags("@treatAsPrivate"); 396 boolean result = (aspTags != null) && (aspTags.length > 0); 397 return result; 398 } 399 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 } 425 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 } 478 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 } 502 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 } 512 513 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 } 535 536 private ProgramElementDoc[] properties(final ClassDoc cd, final boolean filter) { 537 final MethodDoc[] allMethods = cd.methods(filter); 538 final FieldDoc[] allFields = cd.fields(false); 539 540 if (propertiesCache.containsKey(cd)) { 541 return propertiesCache.get(cd); 542 } 543 544 final List<MethodDoc> result = new ArrayList<MethodDoc>(); 545 546 for (final MethodDoc propertyMethod : allMethods) { 547 548 if (!isPropertyMethod(propertyMethod)) { 549 continue; 550 } 551 552 final MethodDoc getter = getterForField(allMethods, propertyMethod); 553 final MethodDoc setter = setterForField(allMethods, propertyMethod); 554 final FieldDoc field = fieldForProperty(allFields, propertyMethod); 555 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 } 565 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 } 582 583 private void addToPropertiesMap(ProgramElementDoc propertyMethod, 584 ProgramElementDoc commentSource) { 585 if (null == propertyMethod || null == commentSource) { 586 return; 587 } 588 final String methodRawCommentText = propertyMethod.getRawCommentText(); 589 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 } 599 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 } 617 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 } 628 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; 639 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 } 651 652 private FieldDoc fieldForProperty(FieldDoc[] fields, MethodDoc property) { 653 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 } 663 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 (!configuration.javafx) { 668 return false; 669 } 670 if (!method.name().endsWith("Property")) { 671 return false; 672 } 673 674 if (! memberIsVisible(method)) { 675 return false; 676 } 677 678 if (pattern.matcher(method.name()).matches()) { 679 return false; 680 } 681 if (method.typeParameters().length > 0) { 682 return false; 683 } 684 return 0 == method.parameters().length 685 && !"void".equals(method.returnType().simpleTypeName()); 686 } 687 688 private void checkOnPropertiesTags(MethodDoc[] members) { 689 for (MethodDoc methodDoc: members) { 690 if (methodDoc.isIncluded()) { 691 for (Tag tag: methodDoc.tags()) { 692 String tagName = tag.name(); 693 if (tagName.equals("@propertySetter") 694 || tagName.equals("@propertyGetter") 695 || tagName.equals("@propertyDescription")) { 696 if (!isPropertyGetterOrSetter(members, methodDoc)) { 697 configuration.message.warning(tag.position(), 698 "doclet.javafx_tag_misuse"); 699 } 700 break; 701 } 702 } 703 } 704 } 705 } 706 707 private boolean isPropertyGetterOrSetter(MethodDoc[] members, 708 MethodDoc methodDoc) { 709 boolean found = false; 710 String propertyName = Util.propertyNameFromMethodName(configuration, methodDoc.name()); 711 if (!propertyName.isEmpty()) { 712 String propertyMethodName = propertyName + "Property"; 713 for (MethodDoc member: members) { 714 if (member.name().equals(propertyMethodName)) { 715 found = true; 716 break; 717 } 718 } 719 } 720 return found; 721 } 722 } 723 724 private class GetterSetter { 725 private final ProgramElementDoc getter; 726 private final ProgramElementDoc setter; 727 728 public GetterSetter(ProgramElementDoc getter, ProgramElementDoc setter) { 729 this.getter = getter; 730 this.setter = setter; 731 } 732 733 public ProgramElementDoc getGetter() { 734 return getter; 735 } 736 737 public ProgramElementDoc getSetter() { 738 return setter; 739 } 740 } 741 742 /** 743 * Return true if this map has no visible members. 744 * 745 * @return true if this map has no visible members. 746 */ 747 public boolean noVisibleMembers() { 748 return noVisibleMembers; 749 } 750 751 private ClassMember getClassMember(MethodDoc member) { 752 for (Iterator<?> iter = memberNameMap.keySet().iterator(); iter.hasNext();) { 753 Object key = iter.next(); 754 if (key instanceof String) { 755 continue; 756 } else if (((ClassMember) key).isEqual(member)) { 757 return (ClassMember) key; 758 } 759 } 760 return new ClassMember(member); 761 } 762 763 /** 764 * Return the key to the member map for the given member. 765 */ 766 private Object getMemberKey(ProgramElementDoc doc) { 767 if (doc.isConstructor()) { 768 return doc.name() + ((ExecutableMemberDoc)doc).signature(); 769 } else if (doc.isMethod()) { 770 return getClassMember((MethodDoc) doc); 771 } else if (doc.isField() || doc.isEnumConstant() || doc.isAnnotationTypeElement()) { 772 return doc.name(); 773 } else { // it's a class or interface 774 String classOrIntName = doc.name(); 775 //Strip off the containing class name because we only want the member name. 776 classOrIntName = classOrIntName.indexOf('.') != 0 ? classOrIntName.substring(classOrIntName.lastIndexOf('.'), classOrIntName.length()) : classOrIntName; 777 return "clint" + classOrIntName; 778 } 779 } 780 }