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 |
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 * |