Sun, 24 Feb 2013 11:36:58 -0800
7112427: The doclet needs to be able to generate JavaFX documentation.
Reviewed-by: jjg
Contributed-by: jan.valenta@oracle.com
1 /*
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.
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 */
26 package com.sun.tools.doclets.internal.toolkit.util;
28 import java.util.*;
29 import java.util.regex.Pattern;
31 import com.sun.javadoc.*;
32 import com.sun.tools.doclets.internal.toolkit.*;
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 {
51 private boolean noVisibleMembers = true;
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_MEMBER_OPTIONAL = 5;
59 public static final int ANNOTATION_TYPE_MEMBER_REQUIRED = 6;
60 public static final int PROPERTIES = 7;
62 /**
63 * The total number of member types is {@value}.
64 */
65 public static final int NUM_MEMBER_TYPES = 8;
67 public static final String STARTLEVEL = "start";
69 /**
70 * List of ClassDoc objects for which ClassMembers objects are built.
71 */
72 private final List<ClassDoc> visibleClasses = new ArrayList<ClassDoc>();
74 /**
75 * Map for each member name on to a map which contains members with same
76 * name-signature. The mapped map will contain mapping for each MemberDoc
77 * onto it's respecive level string.
78 */
79 private final Map<Object,Map<ProgramElementDoc,String>> memberNameMap = new HashMap<Object,Map<ProgramElementDoc,String>>();
81 /**
82 * Map of class and it's ClassMembers object.
83 */
84 private final Map<ClassDoc,ClassMembers> classMap = new HashMap<ClassDoc,ClassMembers>();
86 /**
87 * Type whose visible members are requested. This is the leaf of
88 * the class tree being mapped.
89 */
90 private final ClassDoc classdoc;
92 /**
93 * Member kind: InnerClasses/Fields/Methods?
94 */
95 private final int kind;
97 /**
98 * The configuration this VisibleMemberMap was created with.
99 */
100 private final Configuration configuration;
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>();
109 /**
110 * Construct a VisibleMemberMap of the given type for the given
111 * class.
112 *
113 * @param classdoc the class whose members are being mapped.
114 * @param kind the kind of member that is being mapped.
115 * @param configuration the configuration to use to construct this
116 * VisibleMemberMap. If the field configuration.nodeprecated is true the
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) {
123 this.classdoc = classdoc;
124 this.kind = kind;
125 this.configuration = configuration;
126 new ClassMembers(classdoc, STARTLEVEL).build();
127 }
129 /**
130 * Return the list of visible classes in this map.
131 *
132 * @return the list of visible classes in this map.
133 */
134 public List<ClassDoc> getVisibleClassesList() {
135 sort(visibleClasses);
136 return visibleClasses;
137 }
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 }
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 }
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();
164 }
166 /**
167 * Return the package private members inherited by the class. Only return
168 * if parent is package private and not documented.
169 *
170 * @param configuration the current configuration of the doclet.
171 * @return the package private members inherited by the class.
172 */
173 private List<ProgramElementDoc> getInheritedPackagePrivateMethods(Configuration configuration) {
174 List<ProgramElementDoc> results = new ArrayList<ProgramElementDoc>();
175 for (Iterator<ClassDoc> iter = visibleClasses.iterator(); iter.hasNext(); ) {
176 ClassDoc currentClass = iter.next();
177 if (currentClass != classdoc &&
178 currentClass.isPackagePrivate() &&
179 !Util.isLinkable(currentClass, configuration)) {
180 // Document these members in the child class because
181 // the parent is inaccessible.
182 results.addAll(getMembersFor(currentClass));
183 }
184 }
185 return results;
186 }
188 /**
189 * Return the visible members of the class being mapped. Also append at the
190 * end of the list members that are inherited by inaccessible parents. We
191 * document these members in the child because the parent is not documented.
192 *
193 * @param configuration the current configuration of the doclet.
194 */
195 public List<ProgramElementDoc> getLeafClassMembers(Configuration configuration) {
196 List<ProgramElementDoc> result = getMembersFor(classdoc);
197 result.addAll(getInheritedPackagePrivateMethods(configuration));
198 return result;
199 }
201 /**
202 * Retrn the list of members for the given class.
203 *
204 * @param cd the class to retrieve the list of visible members for.
205 *
206 * @return the list of members for the given class.
207 */
208 public List<ProgramElementDoc> getMembersFor(ClassDoc cd) {
209 ClassMembers clmembers = classMap.get(cd);
210 if (clmembers == null) {
211 return new ArrayList<ProgramElementDoc>();
212 }
213 return clmembers.getMembers();
214 }
216 /**
217 * Sort the given mixed list of classes and interfaces to a list of
218 * classes followed by interfaces traversed. Don't sort alphabetically.
219 */
220 private void sort(List<ClassDoc> list) {
221 List<ClassDoc> classes = new ArrayList<ClassDoc>();
222 List<ClassDoc> interfaces = new ArrayList<ClassDoc>();
223 for (int i = 0; i < list.size(); i++) {
224 ClassDoc cd = list.get(i);
225 if (cd.isClass()) {
226 classes.add(cd);
227 } else {
228 interfaces.add(cd);
229 }
230 }
231 list.clear();
232 list.addAll(classes);
233 list.addAll(interfaces);
234 }
236 private void fillMemberLevelMap(List<ProgramElementDoc> list, String level) {
237 for (int i = 0; i < list.size(); i++) {
238 Object key = getMemberKey(list.get(i));
239 Map<ProgramElementDoc,String> memberLevelMap = memberNameMap.get(key);
240 if (memberLevelMap == null) {
241 memberLevelMap = new HashMap<ProgramElementDoc,String>();
242 memberNameMap.put(key, memberLevelMap);
243 }
244 memberLevelMap.put(list.get(i), level);
245 }
246 }
248 private void purgeMemberLevelMap(List<ProgramElementDoc> list, String level) {
249 for (int i = 0; i < list.size(); i++) {
250 Object key = getMemberKey(list.get(i));
251 Map<ProgramElementDoc, String> memberLevelMap = memberNameMap.get(key);
252 if (level.equals(memberLevelMap.get(list.get(i))))
253 memberLevelMap.remove(list.get(i));
254 }
255 }
257 /**
258 * Represents a class member. We should be able to just use a
259 * ProgramElementDoc instead of this class, but that doesn't take
260 * type variables in consideration when comparing.
261 */
262 private class ClassMember {
263 private Set<ProgramElementDoc> members;
265 public ClassMember(ProgramElementDoc programElementDoc) {
266 members = new HashSet<ProgramElementDoc>();
267 members.add(programElementDoc);
268 }
270 public void addMember(ProgramElementDoc programElementDoc) {
271 members.add(programElementDoc);
272 }
274 public boolean isEqual(MethodDoc member) {
275 for (Iterator<ProgramElementDoc> iter = members.iterator(); iter.hasNext(); ) {
276 MethodDoc member2 = (MethodDoc) iter.next();
277 if (Util.executableMembersEqual(member, member2)) {
278 members.add(member);
279 return true;
280 }
281 }
282 return false;
283 }
284 }
286 /**
287 * A data structure that represents the class members for
288 * a visible class.
289 */
290 private class ClassMembers {
292 /**
293 * The mapping class, whose inherited members are put in the
294 * {@link #members} list.
295 */
296 private ClassDoc mappingClass;
298 /**
299 * List of inherited members from the mapping class.
300 */
301 private List<ProgramElementDoc> members = new ArrayList<ProgramElementDoc>();
303 /**
304 * Level/Depth of inheritance.
305 */
306 private String level;
308 /**
309 * Return list of inherited members from mapping class.
310 *
311 * @return List Inherited members.
312 */
313 public List<ProgramElementDoc> getMembers() {
314 return members;
315 }
317 private ClassMembers(ClassDoc mappingClass, String level) {
318 this.mappingClass = mappingClass;
319 this.level = level;
320 if (classMap.containsKey(mappingClass) &&
321 level.startsWith(classMap.get(mappingClass).level)) {
322 //Remove lower level class so that it can be replaced with
323 //same class found at higher level.
324 purgeMemberLevelMap(getClassMembers(mappingClass, false),
325 classMap.get(mappingClass).level);
326 classMap.remove(mappingClass);
327 visibleClasses.remove(mappingClass);
328 }
329 if (!classMap.containsKey(mappingClass)) {
330 classMap.put(mappingClass, this);
331 visibleClasses.add(mappingClass);
332 }
334 }
336 private void build() {
337 if (kind == CONSTRUCTORS) {
338 addMembers(mappingClass);
339 } else {
340 mapClass();
341 }
342 }
344 private void mapClass() {
345 addMembers(mappingClass);
346 ClassDoc[] interfaces = mappingClass.interfaces();
347 for (int i = 0; i < interfaces.length; i++) {
348 String locallevel = level + 1;
349 ClassMembers cm = new ClassMembers(interfaces[i], locallevel);
350 cm.mapClass();
351 }
352 if (mappingClass.isClass()) {
353 ClassDoc superclass = mappingClass.superclass();
354 if (!(superclass == null || mappingClass.equals(superclass))) {
355 ClassMembers cm = new ClassMembers(superclass,
356 level + "c");
357 cm.mapClass();
358 }
359 }
360 }
362 /**
363 * Get all the valid members from the mapping class. Get the list of
364 * members for the class to be included into(ctii), also get the level
365 * string for ctii. If mapping class member is not already in the
366 * inherited member list and if it is visible in the ctii and not
367 * overridden, put such a member in the inherited member list.
368 * Adjust member-level-map, class-map.
369 */
370 private void addMembers(ClassDoc fromClass) {
371 List<ProgramElementDoc> cdmembers = getClassMembers(fromClass, true);
372 List<ProgramElementDoc> incllist = new ArrayList<ProgramElementDoc>();
373 for (int i = 0; i < cdmembers.size(); i++) {
374 ProgramElementDoc pgmelem = cdmembers.get(i);
375 if (!found(members, pgmelem) &&
376 memberIsVisible(pgmelem) &&
377 !isOverridden(pgmelem, level) &&
378 !isTreatedAsPrivate(pgmelem)) {
379 incllist.add(pgmelem);
380 }
381 }
382 if (incllist.size() > 0) {
383 noVisibleMembers = false;
384 }
385 members.addAll(incllist);
386 fillMemberLevelMap(getClassMembers(fromClass, false), level);
387 }
389 private boolean isTreatedAsPrivate(ProgramElementDoc pgmelem) {
390 if (!configuration.javafx) {
391 return false;
392 }
394 Tag[] aspTags = pgmelem.tags("@treatAsPrivate");
395 boolean result = (aspTags != null) && (aspTags.length > 0);
396 return result;
397 }
399 /**
400 * Is given doc item visible in given classdoc in terms fo inheritance?
401 * The given doc item is visible in the given classdoc if it is public
402 * or protected and if it is package-private if it's containing class
403 * is in the same package as the given classdoc.
404 */
405 private boolean memberIsVisible(ProgramElementDoc pgmdoc) {
406 if (pgmdoc.containingClass().equals(classdoc)) {
407 //Member is in class that we are finding visible members for.
408 //Of course it is visible.
409 return true;
410 } else if (pgmdoc.isPrivate()) {
411 //Member is in super class or implemented interface.
412 //Private, so not inherited.
413 return false;
414 } else if (pgmdoc.isPackagePrivate()) {
415 //Member is package private. Only return true if its class is in
416 //same package.
417 return pgmdoc.containingClass().containingPackage().equals(
418 classdoc.containingPackage());
419 } else {
420 //Public members are always inherited.
421 return true;
422 }
423 }
425 /**
426 * Return all available class members.
427 */
428 private List<ProgramElementDoc> getClassMembers(ClassDoc cd, boolean filter) {
429 if (cd.isEnum() && kind == CONSTRUCTORS) {
430 //If any of these rules are hit, return empty array because
431 //we don't document these members ever.
432 return Arrays.asList(new ProgramElementDoc[] {});
433 }
434 ProgramElementDoc[] members = null;
435 switch (kind) {
436 case ANNOTATION_TYPE_MEMBER_OPTIONAL:
437 members = cd.isAnnotationType() ?
438 filter((AnnotationTypeDoc) cd, false) :
439 new AnnotationTypeElementDoc[] {};
440 break;
441 case ANNOTATION_TYPE_MEMBER_REQUIRED:
442 members = cd.isAnnotationType() ?
443 filter((AnnotationTypeDoc) cd, true) :
444 new AnnotationTypeElementDoc[] {};
445 break;
446 case INNERCLASSES:
447 members = cd.innerClasses(filter);
448 break;
449 case ENUM_CONSTANTS:
450 members = cd.enumConstants();
451 break;
452 case FIELDS:
453 members = cd.fields(filter);
454 break;
455 case CONSTRUCTORS:
456 members = cd.constructors();
457 break;
458 case METHODS:
459 members = cd.methods(filter);
460 checkOnPropertiesTags((MethodDoc[])members);
461 break;
462 case PROPERTIES:
463 members = properties(cd, filter);
464 break;
465 default:
466 members = new ProgramElementDoc[0];
467 }
468 // Deprected members should be excluded or not?
469 if (configuration.nodeprecated) {
470 return Util.excludeDeprecatedMembersAsList(members);
471 }
472 return Arrays.asList(members);
473 }
475 /**
476 * Filter the annotation type members and return either the required
477 * members or the optional members, depending on the value of the
478 * required parameter.
479 *
480 * @param doc The annotation type to process.
481 * @param required
482 * @return the annotation type members and return either the required
483 * members or the optional members, depending on the value of the
484 * required parameter.
485 */
486 private AnnotationTypeElementDoc[] filter(AnnotationTypeDoc doc,
487 boolean required) {
488 AnnotationTypeElementDoc[] members = doc.elements();
489 List<AnnotationTypeElementDoc> targetMembers = new ArrayList<AnnotationTypeElementDoc>();
490 for (int i = 0; i < members.length; i++) {
491 if ((required && members[i].defaultValue() == null) ||
492 ((!required) && members[i].defaultValue() != null)){
493 targetMembers.add(members[i]);
494 }
495 }
496 return targetMembers.toArray(new AnnotationTypeElementDoc[]{});
497 }
499 private boolean found(List<ProgramElementDoc> list, ProgramElementDoc elem) {
500 for (int i = 0; i < list.size(); i++) {
501 ProgramElementDoc pgmelem = list.get(i);
502 if (Util.matches(pgmelem, elem)) {
503 return true;
504 }
505 }
506 return false;
507 }
510 /**
511 * Is member overridden? The member is overridden if it is found in the
512 * same level hierarchy e.g. member at level "11" overrides member at
513 * level "111".
514 */
515 private boolean isOverridden(ProgramElementDoc pgmdoc, String level) {
516 Map<?,String> memberLevelMap = (Map<?,String>) memberNameMap.get(getMemberKey(pgmdoc));
517 if (memberLevelMap == null)
518 return false;
519 String mappedlevel = null;
520 Iterator<String> iterator = memberLevelMap.values().iterator();
521 while (iterator.hasNext()) {
522 mappedlevel = iterator.next();
523 if (mappedlevel.equals(STARTLEVEL) ||
524 (level.startsWith(mappedlevel) &&
525 !level.equals(mappedlevel))) {
526 return true;
527 }
528 }
529 return false;
530 }
532 private ProgramElementDoc[] properties(final ClassDoc cd, final boolean filter) {
533 final MethodDoc[] allMethods = cd.methods(filter);
534 final FieldDoc[] allFields = cd.fields(false);
536 if (propertiesCache.containsKey(cd)) {
537 return propertiesCache.get(cd);
538 }
540 final List<MethodDoc> result = new ArrayList<MethodDoc>();
542 for (final MethodDoc propertyMethod : allMethods) {
544 if (!isPropertyMethod(propertyMethod)) {
545 continue;
546 }
548 final MethodDoc getter = getterForField(allMethods, propertyMethod);
549 final MethodDoc setter = setterForField(allMethods, propertyMethod);
550 final FieldDoc field = fieldForProperty(allFields, propertyMethod);
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 }
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 }
579 private void addToPropertiesMap(ProgramElementDoc propertyMethod,
580 ProgramElementDoc commentSource) {
581 if (null == propertyMethod || null == commentSource) {
582 return;
583 }
584 final String methodRawCommentText = propertyMethod.getRawCommentText();
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 }
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 }
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 }
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;
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 }
648 private FieldDoc fieldForProperty(FieldDoc[] fields, MethodDoc property) {
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 }
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 }
667 if (! memberIsVisible(method)) {
668 return false;
669 }
671 if (pattern.matcher(method.name()).matches()) {
672 return false;
673 }
675 return 0 == method.parameters().length
676 && !"void".equals(method.returnType().simpleTypeName());
677 }
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 }
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 }
715 private class GetterSetter {
716 private final ProgramElementDoc getter;
717 private final ProgramElementDoc setter;
719 public GetterSetter(ProgramElementDoc getter, ProgramElementDoc setter) {
720 this.getter = getter;
721 this.setter = setter;
722 }
724 public ProgramElementDoc getGetter() {
725 return getter;
726 }
728 public ProgramElementDoc getSetter() {
729 return setter;
730 }
731 }
733 /**
734 * Return true if this map has no visible members.
735 *
736 * @return true if this map has no visible members.
737 */
738 public boolean noVisibleMembers() {
739 return noVisibleMembers;
740 }
742 private ClassMember getClassMember(MethodDoc member) {
743 for (Iterator<?> iter = memberNameMap.keySet().iterator(); iter.hasNext();) {
744 Object key = iter.next();
745 if (key instanceof String) {
746 continue;
747 } else if (((ClassMember) key).isEqual(member)) {
748 return (ClassMember) key;
749 }
750 }
751 return new ClassMember(member);
752 }
754 /**
755 * Return the key to the member map for the given member.
756 */
757 private Object getMemberKey(ProgramElementDoc doc) {
758 if (doc.isConstructor()) {
759 return doc.name() + ((ExecutableMemberDoc)doc).signature();
760 } else if (doc.isMethod()) {
761 return getClassMember((MethodDoc) doc);
762 } else if (doc.isField() || doc.isEnumConstant() || doc.isAnnotationTypeElement()) {
763 return doc.name();
764 } else { // it's a class or interface
765 String classOrIntName = doc.name();
766 //Strip off the containing class name because we only want the member name.
767 classOrIntName = classOrIntName.indexOf('.') != 0 ? classOrIntName.substring(classOrIntName.lastIndexOf('.'), classOrIntName.length()) : classOrIntName;
768 return "clint" + classOrIntName;
769 }
770 }
771 }