package org.jmlspecs.openjml.jmldoc;
import java.util.ArrayList;
import java.util.Collections;
import org.jmlspecs.annotation.*;
import org.jmlspecs.openjml.JmlSpecs;
import org.jmlspecs.openjml.JmlSpecs.TypeSpecs;
import org.jmlspecs.openjml.JmlTree.JmlClassDecl;
import org.jmlspecs.openjml.JmlTree.JmlTypeClause;
import org.jmlspecs.openjml.JmlTree.JmlTypeClauseDecl;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.javadoc.Tag;
import com.sun.tools.doclets.formats.html.NestedClassWriterImpl;
import com.sun.tools.doclets.formats.html.SubWriterHolderWriter;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javadoc.ClassDocImpl;
import com.sun.tools.javadoc.DocEnv;
/**
* This class extends its parent class in order to add to the list of Java
* nested classes printed out by Javadoc any nested model classes or interfaces
* supplied by JML.
*
* @author David R. Cok
*/
public class NestedClassWriterJml extends NestedClassWriterImpl {
/** The ClassSymbol (in the JML compilation context) of the class
* whose nested classes are being described.
*/
protected @NonNull ClassSymbol currentClassSym;
// protected @NonNull ClassDoc currentClassDoc;
/** The env corresponding to the input classdoc */
protected @NonNull DocEnv currentDocEnv;
/** The constructor for this kind of writer.
*
* @param writer the actual writer to which calls are delegated
* @param classdoc the class whoise nested classes this writer describes
*/
public NestedClassWriterJml(@NonNull SubWriterHolderWriter writer,
@NonNull ClassDoc classdoc) {
super(writer, classdoc);
// currentClassDoc = classdoc;
currentClassSym = Utils.findNewClassSymbol(classdoc);
currentDocEnv = ((ClassDocImpl)classdoc).docenv();
}
// FIXME - major change in b144
// /** This is overridden to tack onto the end of the nested class information
// * any information about nested JML classes.
// * @param classDoc the classDoc whose nested members are being described
// */
// public void writeMemberSummaryFooter(@NonNull ClassDoc classDoc) {
// super.writeMemberSummaryFooter(classDoc);
// writeJmlNestedClassSummary(classDoc);
// }
// FIXME - major change in b144
// /** This is overridden to tack onto the end of the inherited
// * nested class information
// * any information about inherited nested JML classes.
// * @param classDoc the classDoc whose nested members are being described
// */
// @Override
// public void writeInheritedMemberSummaryFooter(@NonNull ClassDoc classDoc) {
// writeJmlInheritedNestedClassSummaryFooter(classDoc);
// writer.writeInheritedMemberSummaryFooter(classDoc);
// }
/** This is used in place of DocEnv.shouldDocument because model methods are
* marked as synthetic and thus not allowed by DocEnv.
* @param currentDocEnv TODO
* @param sym TODO
* @return TODO
*/
public boolean shouldDocumentModel(DocEnv currentDocEnv, ClassSymbol sym) {
return
// FIXME - do we need the line below - what does it guard against?
//(currentDocEnv.docClasses || currentDocEnv.getClassDoc(sym).tree != null) &&
currentDocEnv.isVisible(sym);
}
/** This writes out information about JML inherited nested classes,
* including writing the header and footer.
* @param classDoc the super class whose members are being described as inherited from currentClassSym
*/
public void writeJmlInheritedNestedClassSummaryFooter(@NonNull ClassDoc classDoc) {
ClassSymbol nsym = Utils.findNewClassSymbol(classDoc);
TypeSpecs tspecs = JmlSpecs.instance(Main.jmlContext).get(nsym);
ArrayList<ClassDoc> list = new ArrayList<ClassDoc>();
// Find all the JML inherited nested classes to describe
for (JmlClassDecl mdecl : tspecs.modelTypes) {
ClassSymbol msym = mdecl.sym;
if (!shouldDocumentModel(currentDocEnv,msym)) continue;
if (!Utils.isInherited(msym,currentClassSym)) continue;
ClassDoc modelClass = new ClassDocJml(((ClassDocImpl)classDoc).docenv(),msym,mdecl.docComment,mdecl,null);
list.add(modelClass);
}
if (!list.isEmpty()) {
writer.br();
writer.strong("Inherited JML model classes and interfaces: ");
Collections.sort(list);
boolean isFirst = true;
// FIXME - major change in b144
// for (ClassDoc nestedClass: list) {
// writer.printInheritedSummaryMember(this, classDoc, nestedClass, isFirst);
// isFirst = false;
// }
}
}
// FIXME - do we need this?
/** check whether this class should be documented. */
public boolean shouldDocument(ClassSymbol sym) {
// special version of currentDocEnv.shouldDocument(msym)
return
(sym.flags_field&Flags.SYNTHETIC) == 0;// && // no synthetics
//(docClasses || getClassDoc(sym).tree != null) &&
//isVisible(sym);
}
/** This writes out information about JML directly nested classes,
* including writing the header and footer.
* @param classDoc the class whose inherited members are being described
*/
public void writeJmlNestedClassSummary(@NonNull ClassDoc classDoc) {
ArrayList<ClassDoc> list = new ArrayList<ClassDoc>();
DocEnv denv = ((ClassDocImpl)classDoc).docenv();
TypeSpecs tspecs = JmlSpecs.instance(Main.jmlContext).get(currentClassSym);
for (JmlClassDecl cdecl : tspecs.modelTypes) {
ClassSymbol msym = cdecl.sym;
//if (!denv.shouldDocument(msym)) continue; // FIXME - explain why the line below instead of this one
if (!denv.isVisible(msym)) continue;
ClassDoc modelClass = new ClassDocJml(((ClassDocImpl)classDoc).docenv(),msym,cdecl.docComment,cdecl,null);
list.add(modelClass);
}
if (list.isEmpty()) return;
Collections.sort(list);
writeJmlNestedClassSummaryHeader(classDoc);
// The following loop is copied with modifications from MemberSummaryBuilder.buildSummary
// FIXME - major change in b144
// for (int i = 0; i<list.size(); i++) {
// ClassDoc member = list.get(i);
// Tag[] firstSentenceTags = member.firstSentenceTags();
// writeMemberSummary(classDoc, member, firstSentenceTags,
// i == 0, i == list.size() - 1);
// }
// FIXME - major change in b144
// super.writeMemberSummaryFooter(classDoc);
}
/** This writes out the header for the block of information about
* nested JML classes.
* @param classDoc the class whose JML nested classes are to be described
*/
public void writeJmlNestedClassSummaryHeader(@NonNull ClassDoc classDoc) {
//printSummaryAnchor(cd);
Utils.writeHeader(writer,this,classDoc,"JML Nested Model Class Summary",2);
}
/** This is overridden in order to include annotation information in the
* nested class summary entry. Immediately after this, the modifiers are written.
* @param member the (class) Doc element whose annotation is to be printed
*/
@Override
protected void printModifier(@NonNull ProgramElementDoc member) {
writer.writeAnnotationInfo(member);
super.printModifier(member);
}
}