/* * @(#)MethodSubWriter.java 1.23 99/05/28 * * Copyright 1997-1999 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. */ package com.sun.tools.doclets.standard; import java.util.*; import com.sun.tools.doclets.*; import com.sun.javadoc.*; /** * * @author Robert Field * @author Atul M Dambalkar */ public class MethodSubWriter extends ExecutableMemberSubWriter { protected MethodSubWriter(SubWriterHolderWriter writer) { super(writer); } public ProgramElementDoc[] members(ClassDoc cd) { return eligibleMembers(cd.methods()); } public void printSummaryLabel(ClassDoc cd) { writer.boldText("doclet.Method_Summary"); } public void printSummaryAnchor(ClassDoc cd) { writer.anchor("method_summary"); } public void printInheritedMembersSummary(ClassDoc cd) { List tcms = Group.asList(cd.methods()); // this class' methods Map imsmap = new HashMap(); // inherited methods List hierarchy = new ArrayList(); if (cd.isClass()) { imsmap = getInheritedMethodMapForClass(cd, tcms, imsmap, hierarchy); } else { imsmap = getInheritedMethodMapForInterface(cd, tcms, imsmap, hierarchy); } if (hierarchy.size() > 0) { for (int i = 0; i < hierarchy.size(); i++) { ClassDoc classkey = (ClassDoc)hierarchy.get(i); List methodlist = (List)imsmap.get(classkey); printInheritedMembersInfo(classkey, methodlist); } } } protected void printInheritedMembersInfo(ClassDoc icd, List members) { if (members.size() > 0) { Collections.sort(members); printInheritedSummaryHeader(icd); printInheritedSummaryMember(icd, (ProgramElementDoc)members.get(0)); for (int i = 1; i < members.size(); ++i) { writer.println(", "); printInheritedSummaryMember(icd, (ProgramElementDoc)members.get(i)); } printInheritedSummaryFooter(icd); } } public void printInheritedSummaryAnchor(ClassDoc cd) { writer.anchor("methods_inherited_from_class_" + cd.qualifiedName()); } public void printInheritedSummaryLabel(ClassDoc cd) { String classlink = writer.getPreQualifiedClassLink(cd); writer.bold(); writer.printText(cd.isClass()? "doclet.Methods_Inherited_From_Class": "doclet.Methods_Inherited_From_Interface", classlink); writer.boldEnd(); } protected void printSummaryType(ProgramElementDoc member) { MethodDoc meth = (MethodDoc)member; printModifierAndType(meth, meth.returnType()); } protected void printReturnTag(Tag[] returns) { if (returns.length > 0) { writer.dt(); writer.boldText("doclet.Returns"); writer.dd(); writer.printInlineComment(returns[0]); } } protected void printOverridden(ClassDoc overridden, MethodDoc method) { if (overridden != null) { String overriddenclasslink = writer.getClassLink(overridden); String methlink = ""; String name = method.name(); writer.dt(); writer.boldText("doclet.Overrides"); writer.dd(); methlink = writer.getClassLink(overridden, name + method.signature(), name, false); writer.printText("doclet.in_class", methlink, overriddenclasslink); } } protected void printTags(ProgramElementDoc member) { MethodDoc method = (MethodDoc)member; ParamTag[] params = method.paramTags(); Tag[] returns = method.tags("return"); Tag[] sinces = method.tags("since"); ThrowsTag[] thrown = method.throwsTags(); SeeTag[] sees = method.seeTags(); ClassDoc[] intfacs = member.containingClass().interfaces(); ClassDoc overridden = method.overriddenClass(); if (intfacs.length > 0 || overridden != null) { printTagsInfoHeader(); printImplementsInfo(method); printOverridden(overridden, method); printTagsInfoFooter(); } if (params.length + returns.length + thrown.length + sinces.length + sees.length > 0) { printTagsInfoHeader(); printParamTags(params); printReturnTag(returns); printThrowsTags(thrown); writer.printSinceTag(method); writer.printSeeTags(method); printTagsInfoFooter(); } else { // no tags are specified MethodDoc taggedMeth = new TaggedMethodFinder(). search(method.containingClass(), method); if (taggedMeth != null) { printTagsFromTaggedMethod(taggedMeth); } } } /** * Print @param, @return, @throws and @see tags only. */ protected void printTagsFromTaggedMethod(MethodDoc method) { ParamTag[] params = method.paramTags(); Tag[] returns = method.tags("return"); ThrowsTag[] thrown = method.throwsTags(); SeeTag[] sees = method.seeTags(); ClassDoc cd = method.containingClass(); String classlink = writer.getClassLink(cd); writer.dd(); writer.boldText(cd.isClass()? "doclet.Tags_From_Class": "doclet.Tags_From_Interface", classlink); writer.ddEnd(); printTagsInfoHeader(); printParamTags(params); printReturnTag(returns); printThrowsTags(thrown); writer.printSeeTags(method); printTagsInfoFooter(); } protected void printTagsInfoHeader() { writer.dd(); writer.dl(); } protected void printTagsInfoFooter() { writer.dlEnd(); writer.ddEnd(); } protected void printImplementsInfo(MethodDoc method) { ClassDoc[] implIntfacs = method.containingClass().interfaces(); if (implIntfacs.length > 0) { MethodDoc implementedMeth = implementedMethod(implIntfacs, method); if (implementedMeth != null) { ClassDoc intfac = implementedMeth.containingClass(); String methlink = ""; String intfaclink = writer.getClassLink(intfac); writer.dt(); writer.boldText("doclet.Specified_By"); writer.dd(); methlink = writer.getDocLink(implementedMeth, implementedMeth.name()); writer.printText("doclet.in_interface", methlink, intfaclink); } } } protected MethodDoc implementedMethod(ClassDoc[] intfacs, MethodDoc method) { for (int i = 0; i < intfacs.length; i++) { MethodDoc found = findMethod(intfacs[i], method); if (found != null) { return found; } ClassDoc[] iin = intfacs[i].interfaces(); found = implementedMethod(iin, method); if (found != null) { return found; } } return null; } protected void printSignature(ExecutableMemberDoc member) { writer.displayLength = 0; writer.pre(); printModifiers(member); printReturnType((MethodDoc)member); bold(member.name()); printParameters(member); printExceptions(member); writer.preEnd(); } protected void printComment(ProgramElementDoc member) { if (member.inlineTags().length > 0) { writer.dd(); writer.printInlineComment(member); } else { MethodDoc method = new CommentedMethodFinder(). search(member.containingClass(), (MethodDoc)member); printCommentFromCommentedMethod(method); } } protected void printCommentFromCommentedMethod(MethodDoc method) { if (method == null) { return; } ClassDoc cd = method.containingClass(); String classlink = writer.getClassLink(cd); writer.dd(); writer.boldText(cd.isClass()? "doclet.Description_From_Class": "doclet.Description_From_Interface", classlink); writer.ddEnd(); writer.dd(); writer.printInlineComment(method); } public void printMembersSummary(ClassDoc cd) { ProgramElementDoc[] members = members(cd); if (members.length > 0) { Arrays.sort(members); printSummaryHeader(cd); for (int i = 0; i < members.length; ++i) { MethodDoc member = (MethodDoc)members[i]; boolean commentChanged = false; String prevRawComment = ""; Tag[] tags = member.inlineTags(); if (tags.length == 0) { prevRawComment = member.getRawCommentText(); MethodDoc meth = new CommentedMethodFinder().search(cd, member); if (meth != null) { //set raw comment text for now. member.setRawCommentText(meth.commentText()); commentChanged = true; } } printSummaryMember(cd, member); if (commentChanged) { // reset it to prevRawComment. member.setRawCommentText(prevRawComment); } } printSummaryFooter(cd); } } abstract class MethodFinder { abstract boolean isCorrectMethod(MethodDoc method); MethodDoc search(ClassDoc cd, MethodDoc method) { MethodDoc meth = searchInterfaces(cd, method); if (meth != null) { return meth; } ClassDoc icd = cd.superclass(); if (icd != null) { meth = findMethod(icd, method); if (meth != null) { if (isCorrectMethod(meth)) { return meth; } } return search(icd, method); } return null; } MethodDoc searchInterfaces(ClassDoc cd, MethodDoc method) { ClassDoc[] iin = cd.interfaces(); for (int i = 0; i < iin.length; i++) { MethodDoc meth = findMethod(iin[i], method); if (meth != null) { if (isCorrectMethod(meth)) { return meth; } } } for (int i = 0; i < iin.length; i++) { MethodDoc meth = searchInterfaces(iin[i], method); if (meth != null) { return meth; } } return null; } } class TaggedMethodFinder extends MethodFinder { boolean isCorrectMethod(MethodDoc method) { return method.paramTags().length + method.tags("return").length + method.throwsTags().length + method.seeTags().length > 0; } } class CommentedMethodFinder extends MethodFinder { boolean isCorrectMethod(MethodDoc method) { return method.inlineTags().length > 0; } } protected void printReturnType(MethodDoc method) { Type type = method.returnType(); if (type != null) { printTypeLink(type); print(' '); } } protected void printHeader(ClassDoc cd) { writer.anchor("method_detail"); writer.printTableHeadingBackground(writer. getText("doclet.Method_Detail")); } protected void printNavSummaryLink(ClassDoc cd, boolean link) { if (link) { writer.printHyperLink("", (cd == null)? "method_summary": "methods_inherited_from_class_" + cd.qualifiedName(), writer.getText("doclet.navMethod")); } else { writer.printText("doclet.navMethod"); } } protected void printNavDetailLink(boolean link) { if (link) { writer.printHyperLink("", "method_detail", writer.getText("doclet.navMethod")); } else { writer.printText("doclet.navMethod"); } } protected Map getInheritedMethodMapForClass(ClassDoc cd, List tcms, Map imsmap, List hierarchy) { ClassDoc icd = cd.superclass(); while (icd != null) { composeInheritedMethodMap(icd, tcms, imsmap, hierarchy); icd = icd.superclass(); } return imsmap; } // IMPORTANT: This code assumes that there is no ambiguity for a method // in the extended interfaces. If there is an ambiguity, Java compiler will // give compilation error for such a case. So the Java code to be // documented has to be compile time error free. protected Map getInheritedMethodMapForInterface(ClassDoc cd, List tims, Map imsmap, List hierarchy) { ClassDoc[] iin = cd.interfaces(); // implemented interfaces for (int i = 0; i < iin.length; i++) { composeInheritedMethodMap(iin[i], tims, imsmap, hierarchy); } for (int i = 0; i < iin.length; i++) { getInheritedMethodMapForInterface(iin[i], tims, imsmap, hierarchy); } return imsmap; } protected void composeInheritedMethodMap(ClassDoc icd, List tcms, Map imsmap, List hierarchy) { MethodDoc[] methods = icd.methods(); List methodlist = new ArrayList(); for (int i = 0; i < methods.length; i++) { if (!contains(tcms, methods[i])) { methodlist.add(methods[i]); tcms.add(methods[i]); } } imsmap.put(icd, methodlist); hierarchy.add(icd); } /** * The simple search. Order `n'. */ protected boolean contains(List tcmethods, MethodDoc method) { for (int i = 0; i < tcmethods.size(); i++) { MethodDoc tcmethod = (MethodDoc)tcmethods.get(i); if (tcmethod.name().equals(method.name()) && tcmethod.signature().equals(method.signature())) { return true; } } return false; } }