1 /* 2 * Copyright (c) 2003, 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 */ 25 26 package com.sun.tools.doclets.internal.toolkit.builders; 27 28 import java.util.*; 29 import java.text.MessageFormat; 30 31 import com.sun.javadoc.*; 32 import com.sun.tools.doclets.internal.toolkit.*; 33 import com.sun.tools.doclets.internal.toolkit.util.*; 34 35 /** 36 * Builds the member summary. 37 * 38 * <p><b>This is NOT part of any supported API. 39 * If you write code that depends on this, you do so at your own risk. 40 * This code and its internal interfaces are subject to change or 41 * deletion without notice.</b> 42 * 43 * @author Jamie Ho 44 * @author Bhavesh Patel (Modified) 45 * @since 1.5 46 */ 47 public class MemberSummaryBuilder extends AbstractMemberBuilder { 48 49 /** 50 * The XML root for this builder. 51 */ 52 public static final String NAME = "MemberSummary"; 53 54 /** 55 * The visible members for the given class. 56 */ 57 private final VisibleMemberMap[] visibleMemberMaps; 58 59 /** 60 * The member summary writers for the given class. 61 */ 62 private MemberSummaryWriter[] memberSummaryWriters; 63 64 /** 65 * The type being documented. 66 */ 67 private final ClassDoc classDoc; 68 69 /** 70 * Construct a new MemberSummaryBuilder. 71 * 72 * @param classWriter the writer for the class whose members are being 73 * summarized. 74 * @param context the build context. 75 */ MemberSummaryBuilder(Context context, ClassDoc classDoc)76 private MemberSummaryBuilder(Context context, ClassDoc classDoc) { 77 super(context); 78 this.classDoc = classDoc; 79 visibleMemberMaps = 80 new VisibleMemberMap[VisibleMemberMap.NUM_MEMBER_TYPES]; 81 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 82 visibleMemberMaps[i] = 83 new VisibleMemberMap( 84 classDoc, 85 i, 86 configuration); 87 } 88 } 89 90 /** 91 * Construct a new MemberSummaryBuilder. 92 * 93 * @param classWriter the writer for the class whose members are being 94 * summarized. 95 * @param context the build context. 96 */ getInstance( ClassWriter classWriter, Context context)97 public static MemberSummaryBuilder getInstance( 98 ClassWriter classWriter, Context context) 99 throws Exception { 100 MemberSummaryBuilder builder = new MemberSummaryBuilder(context, 101 classWriter.getClassDoc()); 102 builder.memberSummaryWriters = 103 new MemberSummaryWriter[VisibleMemberMap.NUM_MEMBER_TYPES]; 104 WriterFactory wf = context.configuration.getWriterFactory(); 105 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 106 builder.memberSummaryWriters[i] = 107 builder.visibleMemberMaps[i].noVisibleMembers() ? 108 null : 109 wf.getMemberSummaryWriter(classWriter, i); 110 } 111 return builder; 112 } 113 114 /** 115 * Construct a new MemberSummaryBuilder. 116 * 117 * @param annotationTypeWriter the writer for the class whose members are 118 * being summarized. 119 * @param configuration the current configuration of the doclet. 120 */ getInstance( AnnotationTypeWriter annotationTypeWriter, Context context)121 public static MemberSummaryBuilder getInstance( 122 AnnotationTypeWriter annotationTypeWriter, Context context) 123 throws Exception { 124 MemberSummaryBuilder builder = new MemberSummaryBuilder(context, 125 annotationTypeWriter.getAnnotationTypeDoc()); 126 builder.memberSummaryWriters = 127 new MemberSummaryWriter[VisibleMemberMap.NUM_MEMBER_TYPES]; 128 WriterFactory wf = context.configuration.getWriterFactory(); 129 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 130 builder.memberSummaryWriters[i] = 131 builder.visibleMemberMaps[i].noVisibleMembers()? 132 null : 133 wf.getMemberSummaryWriter( 134 annotationTypeWriter, i); 135 } 136 return builder; 137 } 138 139 /** 140 * {@inheritDoc} 141 */ getName()142 public String getName() { 143 return NAME; 144 } 145 146 /** 147 * Return the specified visible member map. 148 * 149 * @param type the type of visible member map to return. 150 * @return the specified visible member map. 151 * @throws ArrayIndexOutOfBoundsException when the type is invalid. 152 * @see VisibleMemberMap 153 */ getVisibleMemberMap(int type)154 public VisibleMemberMap getVisibleMemberMap(int type) { 155 return visibleMemberMaps[type]; 156 } 157 158 /** 159 * Return the specified member summary writer. 160 * 161 * @param type the type of member summary writer to return. 162 * @return the specified member summary writer. 163 * @throws ArrayIndexOutOfBoundsException when the type is invalid. 164 * @see VisibleMemberMap 165 */ getMemberSummaryWriter(int type)166 public MemberSummaryWriter getMemberSummaryWriter(int type) { 167 return memberSummaryWriters[type]; 168 } 169 170 /** 171 * Returns a list of methods that will be documented for the given class. 172 * This information can be used for doclet specific documentation 173 * generation. 174 * 175 * @param type the type of members to return. 176 * @return a list of methods that will be documented. 177 * @see VisibleMemberMap 178 */ members(int type)179 public List<ProgramElementDoc> members(int type) { 180 return visibleMemberMaps[type].getLeafClassMembers(configuration); 181 } 182 183 /** 184 * Return true it there are any members to summarize. 185 * 186 * @return true if there are any members to summarize. 187 */ hasMembersToDocument()188 public boolean hasMembersToDocument() { 189 if (classDoc instanceof AnnotationTypeDoc) { 190 return ((AnnotationTypeDoc) classDoc).elements().length > 0; 191 } 192 for (int i = 0; i < VisibleMemberMap.NUM_MEMBER_TYPES; i++) { 193 VisibleMemberMap members = visibleMemberMaps[i]; 194 if (!members.noVisibleMembers()) { 195 return true; 196 } 197 } 198 return false; 199 } 200 201 /** 202 * Build the summary for the enum constants. 203 * 204 * @param node the XML element that specifies which components to document 205 * @param memberSummaryTree the content tree to which the documentation will be added 206 */ buildEnumConstantsSummary(XMLNode node, Content memberSummaryTree)207 public void buildEnumConstantsSummary(XMLNode node, Content memberSummaryTree) { 208 MemberSummaryWriter writer = 209 memberSummaryWriters[VisibleMemberMap.ENUM_CONSTANTS]; 210 VisibleMemberMap visibleMemberMap = 211 visibleMemberMaps[VisibleMemberMap.ENUM_CONSTANTS]; 212 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 213 } 214 215 /** 216 * Build the summary for fields. 217 * 218 * @param node the XML element that specifies which components to document 219 * @param memberSummaryTree the content tree to which the documentation will be added 220 */ buildAnnotationTypeFieldsSummary(XMLNode node, Content memberSummaryTree)221 public void buildAnnotationTypeFieldsSummary(XMLNode node, Content memberSummaryTree) { 222 MemberSummaryWriter writer = 223 memberSummaryWriters[VisibleMemberMap.ANNOTATION_TYPE_FIELDS]; 224 VisibleMemberMap visibleMemberMap = 225 visibleMemberMaps[VisibleMemberMap.ANNOTATION_TYPE_FIELDS]; 226 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 227 } 228 229 /** 230 * Build the summary for the optional members. 231 * 232 * @param node the XML element that specifies which components to document 233 * @param memberSummaryTree the content tree to which the documentation will be added 234 */ buildAnnotationTypeOptionalMemberSummary(XMLNode node, Content memberSummaryTree)235 public void buildAnnotationTypeOptionalMemberSummary(XMLNode node, Content memberSummaryTree) { 236 MemberSummaryWriter writer = 237 memberSummaryWriters[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_OPTIONAL]; 238 VisibleMemberMap visibleMemberMap = 239 visibleMemberMaps[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_OPTIONAL]; 240 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 241 } 242 243 /** 244 * Build the summary for the optional members. 245 * 246 * @param node the XML element that specifies which components to document 247 * @param memberSummaryTree the content tree to which the documentation will be added 248 */ buildAnnotationTypeRequiredMemberSummary(XMLNode node, Content memberSummaryTree)249 public void buildAnnotationTypeRequiredMemberSummary(XMLNode node, Content memberSummaryTree) { 250 MemberSummaryWriter writer = 251 memberSummaryWriters[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_REQUIRED]; 252 VisibleMemberMap visibleMemberMap = 253 visibleMemberMaps[VisibleMemberMap.ANNOTATION_TYPE_MEMBER_REQUIRED]; 254 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 255 } 256 257 /** 258 * Build the summary for the fields. 259 * 260 * @param node the XML element that specifies which components to document 261 * @param memberSummaryTree the content tree to which the documentation will be added 262 */ buildFieldsSummary(XMLNode node, Content memberSummaryTree)263 public void buildFieldsSummary(XMLNode node, Content memberSummaryTree) { 264 MemberSummaryWriter writer = 265 memberSummaryWriters[VisibleMemberMap.FIELDS]; 266 VisibleMemberMap visibleMemberMap = 267 visibleMemberMaps[VisibleMemberMap.FIELDS]; 268 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 269 } 270 271 /** 272 * Build the summary for the fields. 273 */ buildPropertiesSummary(XMLNode node, Content memberSummaryTree)274 public void buildPropertiesSummary(XMLNode node, Content memberSummaryTree) { 275 MemberSummaryWriter writer = 276 memberSummaryWriters[VisibleMemberMap.PROPERTIES]; 277 VisibleMemberMap visibleMemberMap = 278 visibleMemberMaps[VisibleMemberMap.PROPERTIES]; 279 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 280 } 281 282 /** 283 * Build the summary for the nested classes. 284 * 285 * @param node the XML element that specifies which components to document 286 * @param memberSummaryTree the content tree to which the documentation will be added 287 */ buildNestedClassesSummary(XMLNode node, Content memberSummaryTree)288 public void buildNestedClassesSummary(XMLNode node, Content memberSummaryTree) { 289 MemberSummaryWriter writer = 290 memberSummaryWriters[VisibleMemberMap.INNERCLASSES]; 291 VisibleMemberMap visibleMemberMap = 292 visibleMemberMaps[VisibleMemberMap.INNERCLASSES]; 293 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 294 } 295 296 /** 297 * Build the method summary. 298 * 299 * @param node the XML element that specifies which components to document 300 * @param memberSummaryTree the content tree to which the documentation will be added 301 */ buildMethodsSummary(XMLNode node, Content memberSummaryTree)302 public void buildMethodsSummary(XMLNode node, Content memberSummaryTree) { 303 MemberSummaryWriter writer = 304 memberSummaryWriters[VisibleMemberMap.METHODS]; 305 VisibleMemberMap visibleMemberMap = 306 visibleMemberMaps[VisibleMemberMap.METHODS]; 307 addSummary(writer, visibleMemberMap, true, memberSummaryTree); 308 } 309 310 /** 311 * Build the constructor summary. 312 * 313 * @param node the XML element that specifies which components to document 314 * @param memberSummaryTree the content tree to which the documentation will be added 315 */ buildConstructorsSummary(XMLNode node, Content memberSummaryTree)316 public void buildConstructorsSummary(XMLNode node, Content memberSummaryTree) { 317 MemberSummaryWriter writer = 318 memberSummaryWriters[VisibleMemberMap.CONSTRUCTORS]; 319 VisibleMemberMap visibleMemberMap = 320 visibleMemberMaps[VisibleMemberMap.CONSTRUCTORS]; 321 addSummary(writer, visibleMemberMap, false, memberSummaryTree); 322 } 323 324 /** 325 * Build the member summary for the given members. 326 * 327 * @param writer the summary writer to write the output. 328 * @param visibleMemberMap the given members to summarize. 329 * @param summaryTreeList list of content trees to which the documentation will be added 330 */ buildSummary(MemberSummaryWriter writer, VisibleMemberMap visibleMemberMap, LinkedList<Content> summaryTreeList)331 private void buildSummary(MemberSummaryWriter writer, 332 VisibleMemberMap visibleMemberMap, LinkedList<Content> summaryTreeList) { 333 List<ProgramElementDoc> members = new ArrayList<ProgramElementDoc>(visibleMemberMap.getLeafClassMembers( 334 configuration)); 335 if (members.size() > 0) { 336 Collections.sort(members); 337 List<Content> tableContents = new LinkedList<Content>(); 338 for (int i = 0; i < members.size(); i++) { 339 ProgramElementDoc member = members.get(i); 340 final ProgramElementDoc propertyDoc = 341 visibleMemberMap.getPropertyMemberDoc(member); 342 if (propertyDoc != null) { 343 processProperty(visibleMemberMap, member, propertyDoc); 344 } 345 Tag[] firstSentenceTags = member.firstSentenceTags(); 346 if (member instanceof MethodDoc && firstSentenceTags.length == 0) { 347 //Inherit comments from overriden or implemented method if 348 //necessary. 349 DocFinder.Output inheritedDoc = 350 DocFinder.search(new DocFinder.Input((MethodDoc) member)); 351 if (inheritedDoc.holder != null 352 && inheritedDoc.holder.firstSentenceTags().length > 0) { 353 firstSentenceTags = inheritedDoc.holder.firstSentenceTags(); 354 } 355 } 356 writer.addMemberSummary(classDoc, member, firstSentenceTags, 357 tableContents, i); 358 } 359 summaryTreeList.add(writer.getSummaryTableTree(classDoc, tableContents)); 360 } 361 } 362 363 /** 364 * Process the property method, property setter and/or property getter 365 * comment text so that it contains the documentation from 366 * the property field. The method adds the leading sentence, 367 * copied documentation including the defaultValue tag and 368 * the see tags if the appropriate property getter and setter are 369 * available. 370 * 371 * @param visibleMemberMap the members information. 372 * @param member the member which is to be augmented. 373 * @param propertyDoc the original property documentation. 374 */ processProperty(VisibleMemberMap visibleMemberMap, ProgramElementDoc member, ProgramElementDoc propertyDoc)375 private void processProperty(VisibleMemberMap visibleMemberMap, 376 ProgramElementDoc member, 377 ProgramElementDoc propertyDoc) { 378 StringBuilder commentTextBuilder = new StringBuilder(); 379 final boolean isSetter = isSetter(member); 380 final boolean isGetter = isGetter(member); 381 if (isGetter || isSetter) { 382 //add "[GS]ets the value of the property PROPERTY_NAME." 383 if (isSetter) { 384 commentTextBuilder.append( 385 MessageFormat.format( 386 configuration.getText("doclet.PropertySetterWithName"), 387 Util.propertyNameFromMethodName(configuration, member.name()))); 388 } 389 if (isGetter) { 390 commentTextBuilder.append( 391 MessageFormat.format( 392 configuration.getText("doclet.PropertyGetterWithName"), 393 Util.propertyNameFromMethodName(configuration, member.name()))); 394 } 395 if (propertyDoc.commentText() != null 396 && !propertyDoc.commentText().isEmpty()) { 397 commentTextBuilder.append(" \n @propertyDescription "); 398 } 399 } 400 commentTextBuilder.append(propertyDoc.commentText()); 401 402 // copy certain tags 403 List<Tag> allTags = new LinkedList<Tag>(); 404 String[] tagNames = {"@defaultValue", "@since"}; 405 for (String tagName: tagNames) { 406 Tag[] tags = propertyDoc.tags(tagName); 407 if (tags != null) { 408 allTags.addAll(Arrays.asList(tags)); 409 } 410 } 411 for (Tag tag: allTags) { 412 commentTextBuilder.append("\n") 413 .append(tag.name()) 414 .append(" ") 415 .append(tag.text()); 416 } 417 418 //add @see tags 419 if (!isGetter && !isSetter) { 420 MethodDoc getter = (MethodDoc) visibleMemberMap.getGetterForProperty(member); 421 MethodDoc setter = (MethodDoc) visibleMemberMap.getSetterForProperty(member); 422 423 if ((null != getter) 424 && (commentTextBuilder.indexOf("@see #" + getter.name()) == -1)) { 425 commentTextBuilder.append("\n @see #") 426 .append(getter.name()) 427 .append("() "); 428 } 429 430 if ((null != setter) 431 && (commentTextBuilder.indexOf("@see #" + setter.name()) == -1)) { 432 String typeName = setter.parameters()[0].typeName(); 433 // Removal of type parameters and package information. 434 typeName = typeName.split("<")[0]; 435 if (typeName.contains(".")) { 436 typeName = typeName.substring(typeName.lastIndexOf(".") + 1); 437 } 438 commentTextBuilder.append("\n @see #").append(setter.name()); 439 440 if (setter.parameters()[0].type().asTypeVariable() == null) { 441 commentTextBuilder.append("(").append(typeName).append(")"); 442 } 443 commentTextBuilder.append(" \n"); 444 } 445 } 446 member.setRawCommentText(commentTextBuilder.toString()); 447 } 448 /** 449 * Test whether the method is a getter. 450 * @param ped property method documentation. Needs to be either property 451 * method, property getter, or property setter. 452 * @return true if the given documentation belongs to a getter. 453 */ isGetter(ProgramElementDoc ped)454 private boolean isGetter(ProgramElementDoc ped) { 455 final String pedName = ped.name(); 456 return pedName.startsWith("get") || pedName.startsWith("is"); 457 } 458 459 /** 460 * Test whether the method is a setter. 461 * @param ped property method documentation. Needs to be either property 462 * method, property getter, or property setter. 463 * @return true if the given documentation belongs to a setter. 464 */ isSetter(ProgramElementDoc ped)465 private boolean isSetter(ProgramElementDoc ped) { 466 return ped.name().startsWith("set"); 467 } 468 469 /** 470 * Build the inherited member summary for the given methods. 471 * 472 * @param writer the writer for this member summary. 473 * @param visibleMemberMap the map for the members to document. 474 * @param summaryTreeList list of content trees to which the documentation will be added 475 */ buildInheritedSummary(MemberSummaryWriter writer, VisibleMemberMap visibleMemberMap, LinkedList<Content> summaryTreeList)476 private void buildInheritedSummary(MemberSummaryWriter writer, 477 VisibleMemberMap visibleMemberMap, LinkedList<Content> summaryTreeList) { 478 for (Iterator<ClassDoc> iter = visibleMemberMap.getVisibleClassesList().iterator(); 479 iter.hasNext();) { 480 ClassDoc inhclass = iter.next(); 481 if (! (inhclass.isPublic() || 482 Util.isLinkable(inhclass, configuration))) { 483 continue; 484 } 485 if (inhclass == classDoc) { 486 continue; 487 } 488 List<ProgramElementDoc> inhmembers = visibleMemberMap.getMembersFor(inhclass); 489 if (inhmembers.size() > 0) { 490 Collections.sort(inhmembers); 491 Content inheritedTree = writer.getInheritedSummaryHeader(inhclass); 492 Content linksTree = writer.getInheritedSummaryLinksTree(); 493 for (int j = 0; j < inhmembers.size(); ++j) { 494 writer.addInheritedMemberSummary( 495 inhclass.isPackagePrivate() && 496 ! Util.isLinkable(inhclass, configuration) ? 497 classDoc : inhclass, 498 inhmembers.get(j), 499 j == 0, 500 j == inhmembers.size() - 1, linksTree); 501 } 502 inheritedTree.addContent(linksTree); 503 summaryTreeList.add(writer.getMemberTree(inheritedTree)); 504 } 505 } 506 } 507 508 /** 509 * Add the summary for the documentation. 510 * 511 * @param writer the writer for this member summary. 512 * @param visibleMemberMap the map for the members to document. 513 * @param showInheritedSummary true if inherited summary should be documented 514 * @param memberSummaryTree the content tree to which the documentation will be added 515 */ addSummary(MemberSummaryWriter writer, VisibleMemberMap visibleMemberMap, boolean showInheritedSummary, Content memberSummaryTree)516 private void addSummary(MemberSummaryWriter writer, 517 VisibleMemberMap visibleMemberMap, boolean showInheritedSummary, 518 Content memberSummaryTree) { 519 LinkedList<Content> summaryTreeList = new LinkedList<Content>(); 520 buildSummary(writer, visibleMemberMap, summaryTreeList); 521 if (showInheritedSummary) 522 buildInheritedSummary(writer, visibleMemberMap, summaryTreeList); 523 if (!summaryTreeList.isEmpty()) { 524 Content memberTree = writer.getMemberSummaryHeader( 525 classDoc, memberSummaryTree); 526 for (int i = 0; i < summaryTreeList.size(); i++) { 527 memberTree.addContent(summaryTreeList.get(i)); 528 } 529 memberSummaryTree.addContent(writer.getMemberTree(memberTree)); 530 } 531 } 532 } 533