1 /* 2 * Copyright (c) 1999, 2017, 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 jdk.javadoc.internal.doclets.toolkit.util; 27 28 import java.util.*; 29 import java.util.regex.Pattern; 30 31 import javax.lang.model.element.Element; 32 import javax.lang.model.element.ExecutableElement; 33 import javax.lang.model.element.TypeElement; 34 import javax.lang.model.element.VariableElement; 35 import javax.lang.model.type.TypeKind; 36 import javax.lang.model.type.TypeMirror; 37 38 import com.sun.source.doctree.DocCommentTree; 39 import com.sun.source.doctree.DocTree; 40 41 import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; 42 import jdk.javadoc.internal.doclets.toolkit.Messages; 43 44 /** 45 * A data structure that encapsulates the visible members of a particular 46 * type for a given class tree. To use this data structure, you must specify 47 * the type of member you are interested in (nested class, field, constructor 48 * or method) and the leaf of the class tree. The data structure will map 49 * all visible members in the leaf and classes above the leaf in the tree. 50 * 51 * <p><b>This is NOT part of any supported API. 52 * If you write code that depends on this, you do so at your own risk. 53 * This code and its internal interfaces are subject to change or 54 * deletion without notice.</b> 55 * 56 * @author Atul M Dambalkar 57 * @author Jamie Ho (rewrite) 58 */ 59 public class VisibleMemberMap { 60 61 private boolean noVisibleMembers = true; 62 63 public static enum Kind { 64 INNER_CLASSES, 65 ENUM_CONSTANTS, 66 FIELDS, 67 CONSTRUCTORS, 68 METHODS, 69 ANNOTATION_TYPE_FIELDS, 70 ANNOTATION_TYPE_MEMBER_OPTIONAL, 71 ANNOTATION_TYPE_MEMBER_REQUIRED, 72 PROPERTIES; 73 74 public static final EnumSet<Kind> summarySet = EnumSet.range(INNER_CLASSES, METHODS); 75 public static final EnumSet<Kind> detailSet = EnumSet.range(ENUM_CONSTANTS, METHODS); 76 public static String getNavLinkLabels(Kind kind) { 77 switch (kind) { 78 case INNER_CLASSES: 79 return "doclet.navNested"; 80 case ENUM_CONSTANTS: 81 return "doclet.navEnum"; 82 case FIELDS: 83 return "doclet.navField"; 84 case CONSTRUCTORS: 85 return "doclet.navConstructor"; 86 case METHODS: 87 return "doclet.navMethod"; 88 default: 89 throw new AssertionError("unknown kind:" + kind); 90 } 91 } 92 } 93 94 public static final String STARTLEVEL = "start"; 95 96 // properties aren't named setA* or getA* 97 private static final Pattern GETTERSETTERPATTERN = Pattern.compile("[sg]et\\p{Upper}.*"); 98 /** 99 * List of TypeElement objects for which ClassMembers objects are built. 100 */ 101 private final Set<TypeElement> visibleClasses; 102 103 /** 104 * Map for each member name on to a map which contains members with same 105 * name-signature. The mapped map will contain mapping for each MemberDoc 106 * onto it's respecive level string. 107 */ 108 private final Map<Object, Map<Element, String>> memberNameMap = new HashMap<>(); 109 110 /** 111 * Map of class and it's ClassMembers object. 112 */ 113 private final Map<TypeElement, ClassMembers> classMap = new HashMap<>(); 114 115 /** 116 * Type whose visible members are requested. This is the leaf of 117 * the class tree being mapped. 118 */ 119 private final TypeElement typeElement; 120 121 /** 122 * Member kind: InnerClasses/Fields/Methods? 123 */ 124 private final Kind kind; 125 126 /** 127 * The configuration this VisibleMemberMap was created with. 128 */ 129 private final BaseConfiguration configuration; 130 private final Messages messages; 131 private final Utils utils; 132 private final Comparator<Element> comparator; 133 134 private final Map<TypeElement, List<Element>> propertiesCache; 135 private final Map<Element, Element> classPropertiesMap; 136 private final Map<Element, GetterSetter> getterSetterMap; 137 138 /** 139 * Construct a VisibleMemberMap of the given type for the given class. 140 * 141 * @param typeElement whose members are being mapped. 142 * @param kind the kind of member that is being mapped. 143 * @param configuration the configuration to use to construct this 144 * VisibleMemberMap. If the field configuration.nodeprecated is true the 145 * deprecated members are excluded from the map. If the field 146 * configuration.javafx is true the JavaFX features are used. 147 */ 148 public VisibleMemberMap(TypeElement typeElement, 149 Kind kind, 150 BaseConfiguration configuration) { 151 this.typeElement = typeElement; 152 this.kind = kind; 153 this.configuration = configuration; 154 this.messages = configuration.getMessages(); 155 this.utils = configuration.utils; 156 propertiesCache = configuration.propertiesCache; 157 classPropertiesMap = configuration.classPropertiesMap; 158 getterSetterMap = configuration.getterSetterMap; 159 comparator = utils.makeGeneralPurposeComparator(); 160 visibleClasses = new LinkedHashSet<>(); 161 new ClassMembers(typeElement, STARTLEVEL).build(); 162 } 163 164 /** 165 * Return the list of visible classes in this map. 166 * 167 * @return the list of visible classes in this map. 168 */ 169 public SortedSet<TypeElement> getVisibleClasses() { 170 SortedSet<TypeElement> vClasses = new TreeSet<>(comparator); 171 vClasses.addAll(visibleClasses); 172 return vClasses; 173 } 174 175 /** 176 * Returns the property field documentation belonging to the given member. 177 * @param element the member for which the property documentation is needed. 178 * @return the property field documentation, null if there is none. 179 */ 180 public Element getPropertyMemberDoc(Element element) { 181 return classPropertiesMap.get(element); 182 } 183 184 /** 185 * Returns the getter documentation belonging to the given property method. 186 * @param propertyMethod the method for which the getter is needed. 187 * @return the getter documentation, null if there is none. 188 */ 189 public Element getGetterForProperty(Element propertyMethod) { 190 return getterSetterMap.get(propertyMethod).getGetter(); 191 } 192 193 /** 194 * Returns the setter documentation belonging to the given property method. 195 * @param propertyMethod the method for which the setter is needed. 196 * @return the setter documentation, null if there is none. 197 */ 198 public Element getSetterForProperty(Element propertyMethod) { 199 return getterSetterMap.get(propertyMethod).getSetter(); 200 } 201 202 /** 203 * Return the package private members inherited by the class. Only return 204 * if parent is package private and not documented. 205 * 206 * @return the package private members inherited by the class. 207 */ 208 private List<Element> getInheritedPackagePrivateMethods() { 209 List<Element> results = new ArrayList<>(); 210 for (TypeElement currentClass : visibleClasses) { 211 if (currentClass != typeElement && 212 utils.isPackagePrivate(currentClass) && 213 !utils.isLinkable(currentClass)) { 214 // Document these members in the child class because 215 // the parent is inaccessible. 216 results.addAll(classMap.get(currentClass).members); 217 } 218 } 219 return results; 220 } 221 222 /** 223 * Returns a list of visible enclosed members of the type being mapped. 224 * This list may also contain appended members, inherited by inaccessible 225 * super types. These members are documented in the subtype when the 226 * super type is not documented. 227 * 228 * @return a list of visible enclosed members 229 */ 230 231 public List<Element> getLeafMembers() { 232 List<Element> result = new ArrayList<>(); 233 result.addAll(classMap.get(typeElement).members); 234 result.addAll(getInheritedPackagePrivateMethods()); 235 return result; 236 } 237 238 /** 239 * Returns a list of enclosed members for the given type. 240 * 241 * @param typeElement the given type 242 * 243 * @return a list of enclosed members 244 */ 245 public List<Element> getMembers(TypeElement typeElement) { 246 return classMap.get(typeElement).members; 247 } 248 249 public boolean hasMembers(TypeElement typeElement) { 250 return !classMap.get(typeElement).members.isEmpty(); 251 } 252 253 private void fillMemberLevelMap(List<? extends Element> list, String level) { 254 for (Element element : list) { 255 Object key = getMemberKey(element); 256 Map<Element, String> memberLevelMap = memberNameMap.get(key); 257 if (memberLevelMap == null) { 258 memberLevelMap = new HashMap<>(); 259 memberNameMap.put(key, memberLevelMap); 260 } 261 memberLevelMap.put(element, level); 262 } 263 } 264 265 private void purgeMemberLevelMap(Iterable<? extends Element> list, String level) { 266 for (Element element : list) { 267 Object key = getMemberKey(element); 268 Map<Element, String> memberLevelMap = memberNameMap.get(key); 269 if (memberLevelMap != null && level.equals(memberLevelMap.get(element))) 270 memberLevelMap.remove(element); 271 } 272 } 273 274 /** 275 * Represents a class member. 276 */ 277 private class ClassMember { 278 private Set<Element> members; 279 280 public ClassMember(Element element) { 281 members = new HashSet<>(); 282 members.add(element); 283 } 284 285 public boolean isEqual(ExecutableElement member) { 286 for (Element element : members) { 287 if (utils.executableMembersEqual(member, (ExecutableElement) element)) { 288 members.add(member); 289 return true; 290 } 291 } 292 return false; 293 } 294 } 295 296 /** 297 * A data structure that represents the class members for 298 * a visible class. 299 */ 300 private class ClassMembers { 301 302 /** 303 * The mapping class, whose inherited members are put in the 304 * {@link #members} list. 305 */ 306 private final TypeElement typeElement; 307 308 /** 309 * List of members from the mapping class. 310 */ 311 private List<Element> members = null; 312 313 /** 314 * Level/Depth of inheritance. 315 */ 316 private final String level; 317 318 private ClassMembers(TypeElement mappingClass, String level) { 319 this.typeElement = 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 private void build() { 337 if (kind == Kind.CONSTRUCTORS) { 338 addMembers(typeElement); 339 } else { 340 mapClass(); 341 } 342 } 343 344 private void mapClass() { 345 addMembers(typeElement); 346 List<? extends TypeMirror> interfaces = typeElement.getInterfaces(); 347 for (TypeMirror anInterface : interfaces) { 348 String locallevel = level + 1; 349 ClassMembers cm = new ClassMembers(utils.asTypeElement(anInterface), locallevel); 350 cm.mapClass(); 351 } 352 if (utils.isClass(typeElement)) { 353 TypeElement superclass = utils.getSuperClass(typeElement); 354 if (!(superclass == null || typeElement.equals(superclass))) { 355 ClassMembers cm = new ClassMembers(superclass, level + "c"); 356 cm.mapClass(); 357 } 358 } 359 } 360 361 /** 362 * Get all the valid members from the mapping class. Get the list of 363 * members for the class to be included into(ctii), also get the level 364 * string for ctii. If mapping class member is not already in the 365 * inherited member list and if it is visible in the ctii and not 366 * overridden, put such a member in the inherited member list. 367 * Adjust member-level-map, class-map. 368 */ 369 private void addMembers(TypeElement fromClass) { 370 List<Element> result = new ArrayList<>(); 371 for (Element element : getClassMembers(fromClass, true)) { 372 if (memberIsVisible(element)) { 373 if (!isOverridden(element, level)) { 374 if (!utils.isHidden(element)) { 375 result.add(element); 376 } 377 } 378 } 379 } 380 if (members != null) { 381 throw new AssertionError("members should not be null"); 382 } 383 members = Collections.unmodifiableList(result); 384 if (!members.isEmpty()) { 385 noVisibleMembers = false; 386 } 387 fillMemberLevelMap(getClassMembers(fromClass, false), level); 388 } 389 390 /** 391 * Is given element visible in given typeElement in terms of inheritance? The given element 392 * is visible in the given typeElement if it is public or protected and if it is 393 * package-private if it's containing class is in the same package as the given typeElement. 394 */ 395 private boolean memberIsVisible(Element element) { 396 if (utils.getEnclosingTypeElement(element).equals(VisibleMemberMap.this.typeElement)) { 397 //Member is in class that we are finding visible members for. 398 //Of course it is visible. 399 return true; 400 } else if (utils.isPrivate(element)) { 401 //Member is in super class or implemented interface. 402 //Private, so not inherited. 403 return false; 404 } else if (utils.isPackagePrivate(element)) { 405 //Member is package private. Only return true if its class is in 406 //same package. 407 return utils.containingPackage(element).equals(utils.containingPackage(VisibleMemberMap.this.typeElement)); 408 } else { 409 //Public members are always inherited. 410 return true; 411 } 412 } 413 414 /** 415 * Return all available class members. 416 */ 417 private List<? extends Element> getClassMembers(TypeElement te, boolean filter) { 418 if (utils.isEnum(te) && kind == Kind.CONSTRUCTORS) { 419 //If any of these rules are hit, return empty array because 420 //we don't document these members ever. 421 return Collections.emptyList(); 422 } 423 List<? extends Element> list; 424 switch (kind) { 425 case ANNOTATION_TYPE_FIELDS: 426 list = (filter) 427 ? utils.getAnnotationFields(te) 428 : utils.getAnnotationFieldsUnfiltered(te); 429 break; 430 case ANNOTATION_TYPE_MEMBER_OPTIONAL: 431 list = utils.isAnnotationType(te) 432 ? filterAnnotations(te, false) 433 : Collections.emptyList(); 434 break; 435 case ANNOTATION_TYPE_MEMBER_REQUIRED: 436 list = utils.isAnnotationType(te) 437 ? filterAnnotations(te, true) 438 : Collections.emptyList(); 439 break; 440 case INNER_CLASSES: 441 List<TypeElement> xlist = filter 442 ? utils.getInnerClasses(te) 443 : utils.getInnerClassesUnfiltered(te); 444 list = new ArrayList<>(xlist); 445 break; 446 case ENUM_CONSTANTS: 447 list = utils.getEnumConstants(te); 448 break; 449 case FIELDS: 450 if (filter) { 451 list = utils.isAnnotationType(te) 452 ? utils.getAnnotationFields(te) 453 : utils.getFields(te); 454 } else { 455 list = utils.isAnnotationType(te) 456 ? utils.getAnnotationFieldsUnfiltered(te) 457 : utils.getFieldsUnfiltered(te); 458 } 459 break; 460 case CONSTRUCTORS: 461 list = utils.getConstructors(te); 462 break; 463 case METHODS: 464 list = filter ? utils.getMethods(te) : utils.getMethodsUnfiltered(te); 465 checkOnPropertiesTags(list); 466 break; 467 case PROPERTIES: 468 list = properties(te, filter); 469 break; 470 default: 471 list = Collections.emptyList(); 472 } 473 // Deprected members should be excluded or not? 474 if (configuration.nodeprecated) { 475 return utils.excludeDeprecatedMembers(list); 476 } 477 return list; 478 } 479 480 /** 481 * Filter the annotation type members and return either the required 482 * members or the optional members, depending on the value of the 483 * required parameter. 484 * 485 * @param typeElement The annotation type to process. 486 * @param required 487 * @return the annotation type members and return either the required 488 * members or the optional members, depending on the value of the 489 * required parameter. 490 */ 491 private List<Element> filterAnnotations(TypeElement typeElement, boolean required) { 492 List<Element> members = utils.getAnnotationMethods(typeElement); 493 List<Element> targetMembers = new ArrayList<>(); 494 for (Element member : members) { 495 ExecutableElement ee = (ExecutableElement)member; 496 if ((required && ee.getDefaultValue() == null) 497 || ((!required) && ee.getDefaultValue() != null)) { 498 targetMembers.add(member); 499 } 500 } 501 return targetMembers; 502 } 503 504 /** 505 * Is member overridden? The member is overridden if it is found in the 506 * same level hierarchy e.g. member at level "11" overrides member at 507 * level "111". 508 */ 509 private boolean isOverridden(Element element, String level) { 510 Object key = getMemberKey(element); 511 Map<?, String> memberLevelMap = (Map<?, String>) memberNameMap.get(key); 512 if (memberLevelMap == null) 513 return false; 514 for (String mappedlevel : memberLevelMap.values()) { 515 if (mappedlevel.equals(STARTLEVEL) 516 || (level.startsWith(mappedlevel) 517 && !level.equals(mappedlevel))) { 518 return true; 519 } 520 } 521 return false; 522 } 523 524 private List<Element> properties(final TypeElement typeElement, final boolean filter) { 525 final List<ExecutableElement> allMethods = filter 526 ? utils.getMethods(typeElement) 527 : utils.getMethodsUnfiltered(typeElement); 528 final List<VariableElement> allFields = utils.getFieldsUnfiltered(typeElement); 529 530 if (propertiesCache.containsKey(typeElement)) { 531 return propertiesCache.get(typeElement); 532 } 533 534 final List<Element> result = new ArrayList<>(); 535 536 for (final Element propertyMethod : allMethods) { 537 ExecutableElement ee = (ExecutableElement)propertyMethod; 538 if (!isPropertyMethod(ee)) { 539 continue; 540 } 541 542 final ExecutableElement getter = getterForField(allMethods, ee); 543 final ExecutableElement setter = setterForField(allMethods, ee); 544 final VariableElement field = fieldForProperty(allFields, ee); 545 546 addToPropertiesMap(setter, getter, ee, field); 547 getterSetterMap.put(propertyMethod, new GetterSetter(getter, setter)); 548 result.add(ee); 549 } 550 propertiesCache.put(typeElement, result); 551 return result; 552 } 553 554 private void addToPropertiesMap(ExecutableElement setter, 555 ExecutableElement getter, 556 ExecutableElement propertyMethod, 557 VariableElement field) { 558 if (field == null || utils.getDocCommentTree(field) == null) { 559 addToPropertiesMap(setter, propertyMethod); 560 addToPropertiesMap(getter, propertyMethod); 561 addToPropertiesMap(propertyMethod, propertyMethod); 562 } else { 563 addToPropertiesMap(getter, field); 564 addToPropertiesMap(setter, field); 565 addToPropertiesMap(propertyMethod, field); 566 } 567 } 568 569 private void addToPropertiesMap(Element propertyMethod, 570 Element commentSource) { 571 if (null == propertyMethod || null == commentSource) { 572 return; 573 } 574 DocCommentTree docTree = utils.getDocCommentTree(propertyMethod); 575 576 /* The second condition is required for the property buckets. In 577 * this case the comment is at the property method (not at the field) 578 * and it needs to be listed in the map. 579 */ 580 if ((docTree == null) || propertyMethod.equals(commentSource)) { 581 classPropertiesMap.put(propertyMethod, commentSource); 582 } 583 } 584 585 private ExecutableElement getterForField(List<ExecutableElement> methods, 586 ExecutableElement propertyMethod) { 587 final String propertyMethodName = utils.getSimpleName(propertyMethod); 588 final String fieldName = propertyMethodName.substring(0, 589 propertyMethodName.lastIndexOf("Property")); 590 final String fieldNameUppercased = 591 "" + Character.toUpperCase(fieldName.charAt(0)) 592 + fieldName.substring(1); 593 final String getterNamePattern; 594 final String fieldTypeName = propertyMethod.getReturnType().toString(); 595 if ("boolean".equals(fieldTypeName) 596 || fieldTypeName.endsWith("BooleanProperty")) { 597 getterNamePattern = "(is|get)" + fieldNameUppercased; 598 } else { 599 getterNamePattern = "get" + fieldNameUppercased; 600 } 601 602 for (ExecutableElement method : methods) { 603 if (Pattern.matches(getterNamePattern, utils.getSimpleName(method))) { 604 if (method.getParameters().isEmpty() && 605 utils.isPublic(method) || utils.isProtected(method)) { 606 return method; 607 } 608 } 609 } 610 return null; 611 } 612 613 private ExecutableElement setterForField(List<ExecutableElement> methods, 614 ExecutableElement propertyMethod) { 615 final String propertyMethodName = utils.getSimpleName(propertyMethod); 616 final String fieldName = 617 propertyMethodName.substring(0, 618 propertyMethodName.lastIndexOf("Property")); 619 final String fieldNameUppercased = 620 "" + Character.toUpperCase(fieldName.charAt(0)) 621 + fieldName.substring(1); 622 final String setter = "set" + fieldNameUppercased; 623 624 for (ExecutableElement method : methods) { 625 if (setter.equals(utils.getSimpleName(method))) { 626 if (method.getParameters().size() == 1 627 && method.getReturnType().getKind() == TypeKind.VOID 628 && (utils.isPublic(method) || utils.isProtected(method))) { 629 return method; 630 } 631 } 632 } 633 return null; 634 } 635 636 private VariableElement fieldForProperty(List<VariableElement> fields, ExecutableElement property) { 637 638 for (VariableElement field : fields) { 639 final String fieldName = utils.getSimpleName(field); 640 final String propertyName = fieldName + "Property"; 641 if (propertyName.equals(utils.getSimpleName(property))) { 642 return field; 643 } 644 } 645 return null; 646 } 647 648 private boolean isPropertyMethod(ExecutableElement method) { 649 if (!configuration.javafx) { 650 return false; 651 } 652 if (!utils.getSimpleName(method).endsWith("Property")) { 653 return false; 654 } 655 656 if (!memberIsVisible(method)) { 657 return false; 658 } 659 660 if (GETTERSETTERPATTERN.matcher(utils.getSimpleName(method)).matches()) { 661 return false; 662 } 663 if (!method.getTypeParameters().isEmpty()) { 664 return false; 665 } 666 return method.getParameters().isEmpty() 667 && method.getReturnType().getKind() != TypeKind.VOID; 668 } 669 670 private void checkOnPropertiesTags(List<? extends Element> members) { 671 for (Element e: members) { 672 ExecutableElement ee = (ExecutableElement)e; 673 if (utils.isIncluded(ee)) { 674 CommentHelper ch = utils.getCommentHelper(ee); 675 for (DocTree tree: utils.getBlockTags(ee)) { 676 String tagName = ch.getTagName(tree); 677 if (tagName.equals("@propertySetter") 678 || tagName.equals("@propertyGetter") 679 || tagName.equals("@propertyDescription")) { 680 if (!isPropertyGetterOrSetter(members, ee)) { 681 messages.warning(ch.getDocTreePath(tree), 682 "doclet.javafx_tag_misuse"); 683 } 684 break; 685 } 686 } 687 } 688 } 689 } 690 691 private boolean isPropertyGetterOrSetter(List<? extends Element> members, 692 ExecutableElement method) { 693 String propertyName = utils.propertyName(method); 694 if (!propertyName.isEmpty()) { 695 String propertyMethodName = propertyName + "Property"; 696 for (Element member: members) { 697 if (utils.getSimpleName(member).equals(propertyMethodName)) { 698 return true; 699 } 700 } 701 } 702 return false; 703 } 704 } 705 706 public class GetterSetter { 707 private final Element getter; 708 private final Element setter; 709 710 public GetterSetter(Element getter, Element setter) { 711 this.getter = getter; 712 this.setter = setter; 713 } 714 715 public Element getGetter() { 716 return getter; 717 } 718 719 public Element getSetter() { 720 return setter; 721 } 722 } 723 724 /** 725 * Return true if this map has no visible members. 726 * 727 * @return true if this map has no visible members. 728 */ 729 public boolean noVisibleMembers() { 730 return noVisibleMembers; 731 } 732 733 private ClassMember getClassMember(ExecutableElement member) { 734 for (Object key : memberNameMap.keySet()) { 735 if (key instanceof String) { 736 continue; 737 } 738 if (((ClassMember) key).isEqual(member)) { 739 return (ClassMember) key; 740 } 741 } 742 return new ClassMember(member); 743 } 744 745 /** 746 * Return the key to the member map for the given member. 747 */ 748 private Object getMemberKey(Element element) { 749 if (utils.isConstructor(element)) { 750 return utils.getSimpleName(element) + utils.flatSignature((ExecutableElement)element); 751 } else if (utils.isMethod(element)) { 752 return getClassMember((ExecutableElement) element); 753 } else if (utils.isField(element) || utils.isEnumConstant(element) || utils.isAnnotationType(element)) { 754 return utils.getSimpleName(element); 755 } else { // it's a class or interface 756 String classOrIntName = utils.getSimpleName(element); 757 //Strip off the containing class name because we only want the member name. 758 classOrIntName = classOrIntName.indexOf('.') != 0 759 ? classOrIntName.substring(classOrIntName.lastIndexOf('.')) 760 : classOrIntName; 761 return "clint" + classOrIntName; 762 } 763 } 764 }