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

changeset 1606
ccbe7ffdd867
parent 1359
25e14ad23cef
child 2035
a2a5ad0853ed
equal deleted inserted replaced
1605:94e67bed460d 1606:ccbe7ffdd867
1 /* 1 /*
2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this 7 * published by the Free Software Foundation. Oracle designates this
24 */ 24 */
25 25
26 package com.sun.tools.doclets.internal.toolkit.util; 26 package com.sun.tools.doclets.internal.toolkit.util;
27 27
28 import java.util.*; 28 import java.util.*;
29 import java.util.regex.Pattern;
29 30
30 import com.sun.javadoc.*; 31 import com.sun.javadoc.*;
31 import com.sun.tools.doclets.internal.toolkit.*; 32 import com.sun.tools.doclets.internal.toolkit.*;
32 33
33 /** 34 /**
54 public static final int FIELDS = 2; 55 public static final int FIELDS = 2;
55 public static final int CONSTRUCTORS = 3; 56 public static final int CONSTRUCTORS = 3;
56 public static final int METHODS = 4; 57 public static final int METHODS = 4;
57 public static final int ANNOTATION_TYPE_MEMBER_OPTIONAL = 5; 58 public static final int ANNOTATION_TYPE_MEMBER_OPTIONAL = 5;
58 public static final int ANNOTATION_TYPE_MEMBER_REQUIRED = 6; 59 public static final int ANNOTATION_TYPE_MEMBER_REQUIRED = 6;
60 public static final int PROPERTIES = 7;
59 61
60 /** 62 /**
61 * The total number of member types is {@value}. 63 * The total number of member types is {@value}.
62 */ 64 */
63 public static final int NUM_MEMBER_TYPES = 7; 65 public static final int NUM_MEMBER_TYPES = 8;
64 66
65 public static final String STARTLEVEL = "start"; 67 public static final String STARTLEVEL = "start";
66 68
67 /** 69 /**
68 * List of ClassDoc objects for which ClassMembers objects are built. 70 * List of ClassDoc objects for which ClassMembers objects are built.
91 * Member kind: InnerClasses/Fields/Methods? 93 * Member kind: InnerClasses/Fields/Methods?
92 */ 94 */
93 private final int kind; 95 private final int kind;
94 96
95 /** 97 /**
96 * Deprected members should be excluded or not? 98 * The configuration this VisibleMemberMap was created with.
97 */ 99 */
98 private final boolean nodepr; 100 private final Configuration configuration;
101
102 private static final Map<ClassDoc, ProgramElementDoc[]> propertiesCache =
103 new HashMap<ClassDoc, ProgramElementDoc[]>();
104 private static final Map<ProgramElementDoc, ProgramElementDoc> classPropertiesMap =
105 new HashMap<ProgramElementDoc, ProgramElementDoc>();
106 private static final Map<ProgramElementDoc, GetterSetter> getterSetterMap =
107 new HashMap<ProgramElementDoc, GetterSetter>();
99 108
100 /** 109 /**
101 * Construct a VisibleMemberMap of the given type for the given 110 * Construct a VisibleMemberMap of the given type for the given
102 * class. If nodepr is true, exclude the deprecated members from 111 * class.
103 * the map.
104 * 112 *
105 * @param classdoc the class whose members are being mapped. 113 * @param classdoc the class whose members are being mapped.
106 * @param kind the kind of member that is being mapped. 114 * @param kind the kind of member that is being mapped.
107 * @param nodepr if true, exclude the deprecated members from the map. 115 * @param configuration the configuration to use to construct this
108 */ 116 * VisibleMemberMap. If the field configuration.nodeprecated is true the
109 public VisibleMemberMap(ClassDoc classdoc, int kind, boolean nodepr) { 117 * deprecated members are excluded from the map. If the field
118 * configuration.javafx is true the JavaFX features are used.
119 */
120 public VisibleMemberMap(ClassDoc classdoc,
121 int kind,
122 Configuration configuration) {
110 this.classdoc = classdoc; 123 this.classdoc = classdoc;
111 this.nodepr = nodepr;
112 this.kind = kind; 124 this.kind = kind;
125 this.configuration = configuration;
113 new ClassMembers(classdoc, STARTLEVEL).build(); 126 new ClassMembers(classdoc, STARTLEVEL).build();
114 } 127 }
115 128
116 /** 129 /**
117 * Return the list of visible classes in this map. 130 * Return the list of visible classes in this map.
119 * @return the list of visible classes in this map. 132 * @return the list of visible classes in this map.
120 */ 133 */
121 public List<ClassDoc> getVisibleClassesList() { 134 public List<ClassDoc> getVisibleClassesList() {
122 sort(visibleClasses); 135 sort(visibleClasses);
123 return visibleClasses; 136 return visibleClasses;
137 }
138
139 /**
140 * Returns the property field documentation belonging to the given member.
141 * @param ped the member for which the property documentation is needed.
142 * @return the property field documentation, null if there is none.
143 */
144 public ProgramElementDoc getPropertyMemberDoc(ProgramElementDoc ped) {
145 return classPropertiesMap.get(ped);
146 }
147
148 /**
149 * Returns the getter documentation belonging to the given property method.
150 * @param propertyMethod the method for which the getter is needed.
151 * @return the getter documentation, null if there is none.
152 */
153 public ProgramElementDoc getGetterForProperty(ProgramElementDoc propertyMethod) {
154 return getterSetterMap.get(propertyMethod).getGetter();
155 }
156
157 /**
158 * Returns the setter documentation belonging to the given property method.
159 * @param propertyMethod the method for which the setter is needed.
160 * @return the setter documentation, null if there is none.
161 */
162 public ProgramElementDoc getSetterForProperty(ProgramElementDoc propertyMethod) {
163 return getterSetterMap.get(propertyMethod).getSetter();
124 } 164 }
125 165
126 /** 166 /**
127 * Return the package private members inherited by the class. Only return 167 * Return the package private members inherited by the class. Only return
128 * if parent is package private and not documented. 168 * if parent is package private and not documented.
332 List<ProgramElementDoc> incllist = new ArrayList<ProgramElementDoc>(); 372 List<ProgramElementDoc> incllist = new ArrayList<ProgramElementDoc>();
333 for (int i = 0; i < cdmembers.size(); i++) { 373 for (int i = 0; i < cdmembers.size(); i++) {
334 ProgramElementDoc pgmelem = cdmembers.get(i); 374 ProgramElementDoc pgmelem = cdmembers.get(i);
335 if (!found(members, pgmelem) && 375 if (!found(members, pgmelem) &&
336 memberIsVisible(pgmelem) && 376 memberIsVisible(pgmelem) &&
337 !isOverridden(pgmelem, level)) { 377 !isOverridden(pgmelem, level) &&
338 incllist.add(pgmelem); 378 !isTreatedAsPrivate(pgmelem)) {
379 incllist.add(pgmelem);
339 } 380 }
340 } 381 }
341 if (incllist.size() > 0) { 382 if (incllist.size() > 0) {
342 noVisibleMembers = false; 383 noVisibleMembers = false;
343 } 384 }
344 members.addAll(incllist); 385 members.addAll(incllist);
345 fillMemberLevelMap(getClassMembers(fromClass, false), level); 386 fillMemberLevelMap(getClassMembers(fromClass, false), level);
387 }
388
389 private boolean isTreatedAsPrivate(ProgramElementDoc pgmelem) {
390 if (!configuration.javafx) {
391 return false;
392 }
393
394 Tag[] aspTags = pgmelem.tags("@treatAsPrivate");
395 boolean result = (aspTags != null) && (aspTags.length > 0);
396 return result;
346 } 397 }
347 398
348 /** 399 /**
349 * Is given doc item visible in given classdoc in terms fo inheritance? 400 * Is given doc item visible in given classdoc in terms fo inheritance?
350 * The given doc item is visible in the given classdoc if it is public 401 * The given doc item is visible in the given classdoc if it is public
404 case CONSTRUCTORS: 455 case CONSTRUCTORS:
405 members = cd.constructors(); 456 members = cd.constructors();
406 break; 457 break;
407 case METHODS: 458 case METHODS:
408 members = cd.methods(filter); 459 members = cd.methods(filter);
460 checkOnPropertiesTags((MethodDoc[])members);
461 break;
462 case PROPERTIES:
463 members = properties(cd, filter);
409 break; 464 break;
410 default: 465 default:
411 members = new ProgramElementDoc[0]; 466 members = new ProgramElementDoc[0];
412 } 467 }
413 if (nodepr) { 468 // Deprected members should be excluded or not?
469 if (configuration.nodeprecated) {
414 return Util.excludeDeprecatedMembersAsList(members); 470 return Util.excludeDeprecatedMembersAsList(members);
415 } 471 }
416 return Arrays.asList(members); 472 return Arrays.asList(members);
417 } 473 }
418 474
470 return true; 526 return true;
471 } 527 }
472 } 528 }
473 return false; 529 return false;
474 } 530 }
531
532 private ProgramElementDoc[] properties(final ClassDoc cd, final boolean filter) {
533 final MethodDoc[] allMethods = cd.methods(filter);
534 final FieldDoc[] allFields = cd.fields(false);
535
536 if (propertiesCache.containsKey(cd)) {
537 return propertiesCache.get(cd);
538 }
539
540 final List<MethodDoc> result = new ArrayList<MethodDoc>();
541
542 for (final MethodDoc propertyMethod : allMethods) {
543
544 if (!isPropertyMethod(propertyMethod)) {
545 continue;
546 }
547
548 final MethodDoc getter = getterForField(allMethods, propertyMethod);
549 final MethodDoc setter = setterForField(allMethods, propertyMethod);
550 final FieldDoc field = fieldForProperty(allFields, propertyMethod);
551
552 addToPropertiesMap(setter, getter, propertyMethod, field);
553 getterSetterMap.put(propertyMethod, new GetterSetter(getter, setter));
554 result.add(propertyMethod);
555 }
556 final ProgramElementDoc[] resultAray =
557 result.toArray(new ProgramElementDoc[result.size()]);
558 propertiesCache.put(cd, resultAray);
559 return resultAray;
560 }
561
562 private void addToPropertiesMap(MethodDoc setter,
563 MethodDoc getter,
564 MethodDoc propertyMethod,
565 FieldDoc field) {
566 if ((field == null)
567 || (field.getRawCommentText() == null)
568 || field.getRawCommentText().length() == 0) {
569 addToPropertiesMap(setter, propertyMethod);
570 addToPropertiesMap(getter, propertyMethod);
571 addToPropertiesMap(propertyMethod, propertyMethod);
572 } else {
573 addToPropertiesMap(getter, field);
574 addToPropertiesMap(setter, field);
575 addToPropertiesMap(propertyMethod, field);
576 }
577 }
578
579 private void addToPropertiesMap(ProgramElementDoc propertyMethod,
580 ProgramElementDoc commentSource) {
581 if (null == propertyMethod || null == commentSource) {
582 return;
583 }
584 final String methodRawCommentText = propertyMethod.getRawCommentText();
585
586 /* The second condition is required for the property buckets. In
587 * this case the comment is at the property method (not at the field)
588 * and it needs to be listed in the map.
589 */
590 if ((null == methodRawCommentText || 0 == methodRawCommentText.length())
591 || propertyMethod.equals(commentSource)) {
592 classPropertiesMap.put(propertyMethod, commentSource);
593 }
594 }
595
596 private MethodDoc getterForField(MethodDoc[] methods,
597 MethodDoc propertyMethod) {
598 final String propertyMethodName = propertyMethod.name();
599 final String fieldName =
600 propertyMethodName.substring(0,
601 propertyMethodName.lastIndexOf("Property"));
602 final String fieldNameUppercased =
603 "" + Character.toUpperCase(fieldName.charAt(0))
604 + fieldName.substring(1);
605 final String getterNamePattern;
606 final String fieldTypeName = propertyMethod.returnType().toString();
607 if ("boolean".equals(fieldTypeName)
608 || fieldTypeName.endsWith("BooleanProperty")) {
609 getterNamePattern = "(is|get)" + fieldNameUppercased;
610 } else {
611 getterNamePattern = "get" + fieldNameUppercased;
612 }
613
614 for (MethodDoc methodDoc : methods) {
615 if (Pattern.matches(getterNamePattern, methodDoc.name())) {
616 if (0 == methodDoc.parameters().length
617 && (methodDoc.isPublic() || methodDoc.isProtected())) {
618 return methodDoc;
619 }
620 }
621 }
622 return null;
623 }
624
625 private MethodDoc setterForField(MethodDoc[] methods,
626 MethodDoc propertyMethod) {
627 final String propertyMethodName = propertyMethod.name();
628 final String fieldName =
629 propertyMethodName.substring(0,
630 propertyMethodName.lastIndexOf("Property"));
631 final String fieldNameUppercased =
632 "" + Character.toUpperCase(fieldName.charAt(0))
633 + fieldName.substring(1);
634 final String setter = "set" + fieldNameUppercased;
635
636 for (MethodDoc methodDoc : methods) {
637 if (setter.equals(methodDoc.name())) {
638 if (1 == methodDoc.parameters().length
639 && "void".equals(methodDoc.returnType().simpleTypeName())
640 && (methodDoc.isPublic() || methodDoc.isProtected())) {
641 return methodDoc;
642 }
643 }
644 }
645 return null;
646 }
647
648 private FieldDoc fieldForProperty(FieldDoc[] fields, MethodDoc property) {
649
650 for (FieldDoc field : fields) {
651 final String fieldName = field.name();
652 final String propertyName = fieldName + "Property";
653 if (propertyName.equals(property.name())) {
654 return field;
655 }
656 }
657 return null;
658 }
659
660 // properties aren't named setA* or getA*
661 private final Pattern pattern = Pattern.compile("[sg]et\\p{Upper}.*");
662 private boolean isPropertyMethod(MethodDoc method) {
663 if (!method.name().endsWith("Property")) {
664 return false;
665 }
666
667 if (! memberIsVisible(method)) {
668 return false;
669 }
670
671 if (pattern.matcher(method.name()).matches()) {
672 return false;
673 }
674
675 return 0 == method.parameters().length
676 && !"void".equals(method.returnType().simpleTypeName());
677 }
678
679 private void checkOnPropertiesTags(MethodDoc[] members) {
680 for (MethodDoc methodDoc: members) {
681 if (methodDoc.isIncluded()) {
682 for (Tag tag: methodDoc.tags()) {
683 String tagName = tag.name();
684 if (tagName.equals("@propertySetter")
685 || tagName.equals("@propertyGetter")
686 || tagName.equals("@propertyDescription")) {
687 if (!isPropertyGetterOrSetter(members, methodDoc)) {
688 configuration.message.warning(tag.position(),
689 "doclet.javafx_tag_misuse");
690 }
691 break;
692 }
693 }
694 }
695 }
696 }
697
698 private boolean isPropertyGetterOrSetter(MethodDoc[] members,
699 MethodDoc methodDoc) {
700 boolean found = false;
701 String propertyName = Util.propertyNameFromMethodName(methodDoc.name());
702 if (!propertyName.isEmpty()) {
703 String propertyMethodName = propertyName + "Property";
704 for (MethodDoc member: members) {
705 if (member.name().equals(propertyMethodName)) {
706 found = true;
707 break;
708 }
709 }
710 }
711 return found;
712 }
713 }
714
715 private class GetterSetter {
716 private final ProgramElementDoc getter;
717 private final ProgramElementDoc setter;
718
719 public GetterSetter(ProgramElementDoc getter, ProgramElementDoc setter) {
720 this.getter = getter;
721 this.setter = setter;
722 }
723
724 public ProgramElementDoc getGetter() {
725 return getter;
726 }
727
728 public ProgramElementDoc getSetter() {
729 return setter;
730 }
475 } 731 }
476 732
477 /** 733 /**
478 * Return true if this map has no visible members. 734 * Return true if this map has no visible members.
479 * 735 *

mercurial