/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* AbstractDocumentationGenerator.java
* Creation date: Sep 27, 2005.
* By: Joseph Wong
*/
package org.openquark.cal.caldoc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Logger;
import org.openquark.cal.compiler.ClassInstance;
import org.openquark.cal.compiler.ClassInstanceIdentifier;
import org.openquark.cal.compiler.ClassMethod;
import org.openquark.cal.compiler.DataConstructor;
import org.openquark.cal.compiler.Function;
import org.openquark.cal.compiler.FunctionalAgent;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.ModuleNameResolver;
import org.openquark.cal.compiler.ModuleTypeInfo;
import org.openquark.cal.compiler.QualifiedName;
import org.openquark.cal.compiler.Scope;
import org.openquark.cal.compiler.ScopedEntity;
import org.openquark.cal.compiler.ScopedEntityNamingPolicy;
import org.openquark.cal.compiler.SourceModel;
import org.openquark.cal.compiler.SourceModelTraverser;
import org.openquark.cal.compiler.TypeClass;
import org.openquark.cal.compiler.TypeConstructor;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
import org.openquark.cal.services.ProgramModelManager;
import org.openquark.util.Pair;
/**
* This is a base class that encapsulates some of the high level data structure
* traversal for generating documentation from CALDoc/metadata. It abstracts out
* this traversal detail so that subclasses can focus upon
* output-format-specific tasks such as generating appropriate formatting
* markups.
* <p>
*
* Note that it is completely possible to write a documentation generator from
* scratch without subclassing this class. All features accessed by this class
* are themselves exposed through the CAL API.
* <p>
*
* The class is organized in a way that is similar to a visitor in the visitor
* pattern, in that the implementation of the abstract methods are called to
* "visit" a particular CAL entity to generate its documentation.
* <p>
*
* The current visitation pattern is:
* <pre>
* generateDoc
* - for each module: prepareGenerationForModule
*
* beginDoc
*
* generateModuleDoc
* beginModuleDoc
*
* generateModuleHeaderSection
* generateModuleDescription
* beginImportedModulesList
* generateImportedModule
* endImportedModuleList
* beginFriendModulesList
* generateFriendModule
* endFriendModuleList
* beginDirectlyDependentModulesList
* generateDirectlyDependentModule
* endDirectlyDependentModulesList
* beginIndirectlyDependentModulesList
* generateIndirectlyDependentModule
* endIndirectlyDependentModulesList
*
* generateModuleOverviewSection
* beginModuleOverviewSection
*
* beginTypeConsOverviewSection
* generateTypeConsOverview
* generateTypeConsOverviewHeader
* beginDataConsOverviewList
* generateDataConsOverview
* endDataConsOverviewList
* generateTypeConsOverviewFooter
* endTypeConsOverviewSection
*
* beginFunctionsOverviewSection
* generateFunctionOverview
* endFunctionsOverviewSection
*
* beginTypeClassOverviewSection
* generateTypeClassOverview
* generateTypeClassOverviewHeader
* beginClassMethodOverviewList
* generateClassMethodOverview
* endClassMethodOverviewList
* generateTypeClassOverviewFooter
* endTypeClassOverviewSection
*
* beginClassInstancesOverviewSection
* generateClassInstanceOverview
* generateClassInstanceOverviewHeader
* beginInstanceMethodOverviewList
* generateInstanceMethodOverview
* endInstanceMethodOverviewList
* generateClassInstanceOverviewFooter
* endClassInstancesOverviewSection
*
* endModuleOverviewSection
*
* generateModuleDetailsSection
* generateTypeConsDocSection
* beginTypeConsDocSection
*
* generateTypeConsDoc
* generateTypeConsDocHeader
*
* beginDataConsDocList
* generateDataConsDoc
* endDataConsDocList
*
* beginKnownInstancesList
* generateKnownInstance
* endKnownInstancesList
*
* generateTypeConsDocFooter
*
* endTypeConsDocSection
*
* generateFunctionsDocSection
* beginFunctionsDocSection
*
* generateFunctionDoc
*
* endFunctionsDocSection
*
* generateTypeClassesDocSection
* beginTypeClassesDocSection
*
* generateTypeClassDoc
* generateTypeClassDocHeader
*
* beginClassMethodDocList
* generateClassMethodDoc
* endClassMethodDocList
*
* beginKnownInstancesList
* generateKnownInstance
* endKnownInstancesList
*
* generateTypeClassDocFooter
*
* endTypeClassesDocSection
*
* generateClassInstancesDocSection
* beginClassInstancesDocSection
*
* generateClassInstanceDoc
* generateClassInstanceDocHeader
*
* beginInstanceMethodDocList
* generateInstanceMethodDoc
* endInstanceMethodDocList
*
* generateClassInstanceDocFooter
*
* endClassInstancesDocSection
*
* endModuleDoc
*
* genereateUsageIndices
* beginTypeConsUsageDoc
*
* generateUsageIndiciesForTypeConsOrTypeClass
* generateUsageIndiciesForDependentModule
* beginUsageDocGroupForDependentModule
*
* beginUsageDocArgTypeIndex
* generateUsageDocArgTypeIndexEntry
* endUsageDocArgTypeIndex
*
* beginUsageDocReturnTypeIndex
* generateUsageDocArgTypeIndexEntry
* endUsageDocReturnTypeIndex
*
* beginUsageDocInstanceIndex
* generateUsageDocInstanceIndexEntry
* endUsageDocInstanceIndex
*
* endUsageDocGroupForDependentModule
*
* endTypeConsUsageDoc
*
* beginTypeClassUsageDoc
*
* generateUsageIndiciesForTypeConsOrTypeClass
* generateUsageIndiciesForDependentModule
* beginUsageDocGroupForDependentModule
*
* beginUsageDocArgTypeIndex
* generateUsageDocArgTypeIndexEntry
* endUsageDocArgTypeIndex
*
* beginUsageDocReturnTypeIndex
* generateUsageDocArgTypeIndexEntry
* endUsageDocReturnTypeIndex
*
* beginUsageDocInstanceIndex
* generateUsageDocInstanceIndexEntry
* endUsageDocInstanceIndex
*
* endUsageDocGroupForDependentModule
*
* endTypeClassUsageDoc
*
* endDoc
* </pre>
*
* @author Joseph Wong
*/
abstract class AbstractDocumentationGenerator {
/** The program model manager associated with this instance. */
final ProgramModelManager programModelManager;
/** The label maker for making labels (aka anchors in HTML). */
final DocLabelMaker labelMaker;
/** The filter to use for excluding modules and entries. */
final DocumentationGenerationFilter filter;
/** The logger for logging status and error messages. */
final Logger logger;
/** The map containing an index entry for each module. */
final TreeMap<ModuleName, PerModuleIndices> moduleIndices;
/**
* The map mapping a qualified type name to a map from module names to pairs
* of sets of index entries which respectively refer to the type in their
* argument types and refer to the type in their return types.
* <p>
* In other words, it represents the nested mapping of:
* <p>
* type name -> dependent module name -> ([arg type index entries], [return type index entries])
*/
final Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> typeConsUsageIndices = new HashMap<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>>();
/**
* The map mapping a qualified type class name to a map from module names to pairs
* of sets of index entries which respectively refer to the type class in their
* argument types and refer to the type in their return types.
* <p>
* In other words, it represents the nested mapping of:
* <p>
* type class name -> dependent module name -> ([arg type index entries], [return type index entries])
*/
final Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> classUsageIndices = new HashMap<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>>();
/** The map from a module name to a set of names of modules that import that module. */
final LinkedHashMap<ModuleName, Set<ModuleName>> moduleNameToDirectlyDependentModuleNames;
/** Whether to build usage indices. */
final boolean shouldGenerateUsageIndices;
/** A map from a ClassInstance to the minimum scope of its instance class and instance type, as previously cached. */
final IdentityHashMap<ClassInstance, Scope> classInstanceMinScopeCache = new IdentityHashMap<ClassInstance, Scope>();
/** The module name resolver initialized with the names of modules to be documented. */
private final ModuleNameResolver moduleNameResolverForDocumentedModules;
/**
* This is a factory class for creating labels for hyperlink-able entities. Such
* labels can be used for creating hyperlinks or cross-references.
*
* @author Joseph Wong
*/
static final class DocLabelMaker {
/**
* Creates a label for a module.
* @param moduleTypeInfo the ModuleTypeInfo of the module.
* @return the label for the module.
*/
String getLabel(ModuleTypeInfo moduleTypeInfo) {
return getModuleLabel(moduleTypeInfo.getModuleName());
}
/**
* Creates a label for a module.
* @param moduleName the name of the module.
* @return the label for the module.
*/
String getModuleLabel(ModuleName moduleName) {
return "module:" + moduleName;
}
/**
* Creates a label for a functional agent (FunctionalAgent: function/class method/data constructor).
* @param entity the entity.
* @return the label for the entity.
*/
String getLabel(FunctionalAgent entity) {
if (entity instanceof Function || entity instanceof ClassMethod) {
return getFunctionOrClassMethodLabel(entity.getName().getUnqualifiedName());
} else if (entity instanceof DataConstructor) {
return getDataConsLabel(entity.getName().getUnqualifiedName());
} else {
throw new IllegalArgumentException();
}
}
/**
* Creates a label for a type constructor.
* @param typeConstructor the type constructor's entity.
* @return the label for the type constructor.
*/
String getLabel(TypeConstructor typeConstructor) {
return getTypeConsLabel(typeConstructor.getName().getUnqualifiedName());
}
/**
* Creates a label for a type constructor.
* @param unqualifiedName the type constructor's name.
* @return the label for the type constructor.
*/
String getTypeConsLabel(String unqualifiedName) {
return "typeCons:" + unqualifiedName;
}
/**
* Creates a label for a data constructor.
* @param dataConstructor the data constructor's entity.
* @return the label for the data constructor.
*/
String getLabel(DataConstructor dataConstructor) {
return getDataConsLabel(dataConstructor.getName().getUnqualifiedName());
}
/**
* Creates a label for a data constructor.
* @param unqualifiedName the data constructor's name.
* @return the label for the data constructor.
*/
String getDataConsLabel(String unqualifiedName) {
return "dataCons:" + unqualifiedName;
}
/**
* Creates a label for a function.
* @param function the function's entity.
* @return the label for the function.
*/
String getLabel(Function function) {
return getFunctionOrClassMethodLabel(function.getName().getUnqualifiedName());
}
/**
* Creates a label for a function.
* @param unqualifiedName the function's name.
* @return the label for the function.
*/
String getFunctionOrClassMethodLabel(String unqualifiedName) {
return "functionOrMethod:" + unqualifiedName;
}
/**
* Creates a label for a type class.
* @param typeClass the type class's entity.
* @return the label for the type class.
*/
String getLabel(TypeClass typeClass) {
return getTypeClassLabel(typeClass.getName().getUnqualifiedName());
}
/**
* Creates a label for a type class.
* @param unqualifiedName the type class's name.
* @return the label for the type class.
*/
String getTypeClassLabel(String unqualifiedName) {
return "typeClass:" + unqualifiedName;
}
/**
* Creates a label for a class method.
* @param classMethod the class method's entity.
* @return the label for the class method.
*/
String getLabel(ClassMethod classMethod) {
return getFunctionOrClassMethodLabel(classMethod.getName().getUnqualifiedName());
}
/**
* Creates a label for a class instance.
* @param classInstance the class instance's entity.
* @return the label for the class instance.
*/
String getLabel(ClassInstance classInstance) {
return getClassInstanceLabel(classInstance.getIdentifier());
}
/**
* Creates a label for a class instance.
* @param identifier the class instance's identifier.
* @return the label for the class instance.
*/
String getClassInstanceLabel(ClassInstanceIdentifier identifier) {
return "instance:" + identifier.getTypeClassName() + ":" + identifier.getTypeIdentifier().replace('$', ':'); // the $ character is not allowed as an HTML element ID
}
/**
* Creates a label for an instance method.
* @param classInstance the entity of the instance method's class instance.
* @param instanceMethodName the instance method's name.
* @return the label for the instance method.
*/
String getLabel(ClassInstance classInstance, String instanceMethodName) {
return getInstanceMethodLabel(classInstance.getIdentifier(), instanceMethodName);
}
/**
* Creates a label for an instance method.
* @param identifier the identifier of the instance method's class instance.
* @param instanceMethodName the instance method's name.
* @return the label for the instance method.
*/
String getInstanceMethodLabel(ClassInstanceIdentifier identifier, String instanceMethodName) {
return "instanceMethod:" + identifier.getTypeClassName() + ":" + identifier.getTypeIdentifier().replace('$', ':') + ":" + instanceMethodName; // the $ character is not allowed as an HTML element ID
}
}
/**
* This class encapsulates the various indices we build on a per-module basis.
*
* @author Joseph Wong
*/
private static final class PerModuleIndices {
/** Private constructor. */
private PerModuleIndices() {}
/** The list containing index entries for types. */
private final List<IndexEntry> typeIndex = new ArrayList<IndexEntry>();
/** The list containing index entries for functions, data constructors, and class methods. */
private final List<IndexEntry> functionalAgentIndex = new ArrayList<IndexEntry>();
/** The list containing index entries for classes. */
private final List<IndexEntry> typeClassIndex = new ArrayList<IndexEntry>();
/** The list containing index entries for instances. */
private final List<IndexEntry> instanceIndex = new ArrayList<IndexEntry>();
}
/**
* This class encapsulates an index entry - a display name, and the label the entry refers to.
*
* @author Joseph Wong
*/
static class IndexEntry {
/** The display name to be displayed on this index entry. */
private final String displayName;
/** The label this entry refers to. */
private final String label;
/** The CAL scope of this entry. Could be null. */
private final Scope scope;
/** The kind of entry this is. */
private final Kind kind;
/** A typesafe enumeration of the possible kinds of index entries. */
static class Kind {
static final Kind TYPE = new Kind("type");
static final Kind FUNCTIONAL_AGENT = new Kind("functionalAgent");
static final Kind TYPE_CLASS = new Kind("typeClass");
static final Kind INSTANCE = new Kind("instance");
/** The name of the kind. */
private final String name;
/** Private constructor. */
private Kind(String name) {
this.name = name;
}
/** {@inheritDoc} **/
@Override
public String toString() {
return name;
}
}
/**
* Constructs an index entry.
* @param displayName the display name.
* @param label the label the entry refers to.
* @param scope the CAL scope of the entry. Could be null.
* @param kind the kind of entry this is.
*/
IndexEntry(String displayName, String label, Scope scope, Kind kind) {
if (displayName == null || label == null || kind == null) {
throw new NullPointerException();
}
this.displayName = displayName;
this.label = label;
this.scope = scope;
this.kind = kind;
}
/**
* @return the display name of this entry.
*/
String getDisplayName() {
return displayName;
}
/**
* @return the label of this entry.
*/
String getLabel() {
return label;
}
/**
* @return the CAL scope of this entry. Could be null.
*/
Scope getScope() {
return scope;
}
/**
* @return the kind of entry this is.
*/
Kind getKind() {
return kind;
}
}
/**
* A class which traverses a type signature and associates the given entity with its
* various argument types and return type.
*
* @author Joseph Wong
*/
private final class EnvEntityProcessorForArgAndReturnTypeIndices extends SourceModelTraverser<Void, Void> {
/** The entity to be associated. */
private final FunctionalAgent entity;
/** Whether we are currently traversing the return type. */
private boolean inReturnType;
/** A map from type variables to their type class constraints. */
private Map<String, List<SourceModel.Name.TypeClass>> typeVarToConstrainingClassesMap = new HashMap<String, List<SourceModel.Name.TypeClass>>();
/**
* Constructs an EnvEntityProcessorForArgAndReturnTypeIndices instance.
* @param entity the entity to be associated.
*/
private EnvEntityProcessorForArgAndReturnTypeIndices(FunctionalAgent entity) {
this.entity = entity;
}
/**
* Returns the list of the names of the constraining classes for a type variable.
* @param typeVarName the type variable.
* @return the corresponding list of the names of the constraining classes.
*/
private List<SourceModel.Name.TypeClass> getConstrainingClassNames(String typeVarName) {
List<SourceModel.Name.TypeClass> theList = typeVarToConstrainingClassesMap.get(typeVarName);
if (theList == null) {
theList = new ArrayList<SourceModel.Name.TypeClass>();
typeVarToConstrainingClassesMap.put(typeVarName, theList);
}
return theList;
}
/**
* Returns the appropriate index based on whether we are currently traversing the return type.
* @param usageIndices the usage indices map.
* @param qualifiedName the name of the type constructor whose index is to be returned.
* @return the requested index.
*/
private TreeSet<FunctionalAgent> getAppropriateIndex(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, QualifiedName qualifiedName) {
ModuleName entityModuleName = entity.getName().getModuleName();
if (inReturnType) {
return getReturnTypeIndex(usageIndices, qualifiedName, entityModuleName);
} else {
return getArgTypeIndex(usageIndices, qualifiedName, entityModuleName);
}
}
/**
* Returns the appropriate index based on whether we are currently traversing the return type.
* @param usageIndices the usage indices map.
* @param moduleName the module name of the type constructor whose index is to be returned.
* @param unqualifiedName the unqualified name of the type constructor whose index is to be returned.
* @return the requested index.
*/
private TreeSet<FunctionalAgent> getAppropriateIndex(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, ModuleName moduleName, String unqualifiedName) {
ModuleName entityModuleName = entity.getName().getModuleName();
if (inReturnType) {
return getReturnTypeIndex(usageIndices, moduleName, unqualifiedName, entityModuleName);
} else {
return getArgTypeIndex(usageIndices, moduleName, unqualifiedName, entityModuleName);
}
}
/**
* {@inheritDoc}
*/
@Override
public Void visit_TypeExprDefn_List(SourceModel.TypeExprDefn.List list, Void arg) {
verifyArg(list, "list");
getAppropriateIndex(typeConsUsageIndices, CAL_Prelude.TypeConstructors.List).add(entity);
return super.visit_TypeExprDefn_List(list, arg);
}
/**
* {@inheritDoc}
*/
@Override
public Void visit_TypeExprDefn_TypeCons(SourceModel.TypeExprDefn.TypeCons cons, Void arg) {
verifyArg(cons, "cons");
// NOTE: We require that the type cons name be fully qualified with a non-null module name.
getAppropriateIndex(typeConsUsageIndices, SourceModel.Name.Module.toModuleName(cons.getTypeConsName().getModuleName()), cons.getTypeConsName().getUnqualifiedName()).add(entity);
return super.visit_TypeExprDefn_TypeCons(cons, arg);
}
/**
* {@inheritDoc}
*/
@Override
public Void visit_TypeExprDefn_Unit(SourceModel.TypeExprDefn.Unit unit, Void arg) {
verifyArg(unit, "unit");
getAppropriateIndex(typeConsUsageIndices, CAL_Prelude.TypeConstructors.Unit).add(entity);
return super.visit_TypeExprDefn_Unit(unit, arg);
}
/**
* {@inheritDoc}
*/
@Override
public Void visit_Constraint_TypeClass(SourceModel.Constraint.TypeClass typeClassConstraint, Void arg) {
verifyArg(typeClassConstraint, "typeClass");
SourceModel.Name.TypeClass typeClassName = typeClassConstraint.getTypeClassName();
String typeVarName = typeClassConstraint.getTypeVarName().getName();
// we make a note that the type variable has this particular class constraint
getConstrainingClassNames(typeVarName).add(typeClassName);
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Void visit_TypeExprDefn_TypeVar(SourceModel.TypeExprDefn.TypeVar var, Void arg) {
verifyArg(var, "var");
String typeVarName = var.getTypeVarName().getName();
// we obtain the list of the class constraints on this type variable, and for each one
// associate the entity with it in the appropriate index
List<SourceModel.Name.TypeClass> constrainingClassNames = getConstrainingClassNames(typeVarName);
for (int i = 0, n = constrainingClassNames.size(); i < n; i++) {
SourceModel.Name.TypeClass constrainingClassName = constrainingClassNames.get(i);
// NOTE: We require that the type class name be fully qualified with a non-null module name.
QualifiedName qualifiedClassName = QualifiedName.make(SourceModel.Name.Module.toModuleName(constrainingClassName.getModuleName()), constrainingClassName.getUnqualifiedName());
getAppropriateIndex(classUsageIndices, qualifiedClassName).add(entity);
}
return null;
}
/**
* Processes the type signature being visited and associate the entity encapsulated by this
* visitor with the type classes and type constructors contained within this signature.
*/
@Override
public Void visit_TypeSignature(SourceModel.TypeSignature signature, Void arg) {
verifyArg(signature, "signature");
// process the type constraints
int nConstraints = signature.getNConstraints();
for (int i = 0; i < nConstraints; i++) {
signature.getNthConstraint(i).accept(this, arg);
}
// having processed the type constraints, proceed to the type expression
SourceModel.TypeExprDefn typeExpr = signature.getTypeExprDefn();
// first we traverse each argument type of the function type
inReturnType = false;
while (typeExpr instanceof SourceModel.TypeExprDefn.Function) {
SourceModel.TypeExprDefn.Function functionTypeExpr = (SourceModel.TypeExprDefn.Function)typeExpr;
// process the domain type
functionTypeExpr.getDomain().accept(this, arg);
// then loop on the codomain type
typeExpr = functionTypeExpr.getCodomain();
}
// then we traverse the return type
inReturnType = true;
typeExpr.accept(this, arg);
return null;
}
}
/**
* A comparator to sort scoped entities so that 1) different modules are sorted according to
* a module name ordering, and 2) the entities are sorted in a case-insensitive manner.
*
* @author Joseph Wong
*/
private static final class ScopedEntityComparator implements Comparator<ScopedEntity> {
/** Singleton instance. */
private static final ScopedEntityComparator INSTANCE = new ScopedEntityComparator();
/** Private constructor. */
private ScopedEntityComparator() {}
/** {@inheritDoc} */
public int compare(ScopedEntity a, ScopedEntity b) {
int moduleComparison = a.getName().getModuleName().compareTo(b.getName().getModuleName());
if (moduleComparison != 0) {
return moduleComparison;
}
int ignoreCaseComparison = a.getName().getUnqualifiedName().compareToIgnoreCase(b.getName().getUnqualifiedName());
if (ignoreCaseComparison != 0) {
return ignoreCaseComparison;
}
return a.getName().getUnqualifiedName().compareTo(b.getName().getUnqualifiedName());
}
}
/**
* A comparator to sort class instances firstly by the type class of the instance, and then by
* the instance type's string representation.
*
* @author Joseph Wong
*/
private static final class ClassInstanceComparator implements Comparator<ClassInstance> {
/** {@inheritDoc} */
public int compare(ClassInstance a, ClassInstance b) {
QualifiedName aTypeClassName = a.getTypeClass().getName();
QualifiedName bTypeClassName = b.getTypeClass().getName();
/// first compare the type classes' names in a case-insensitive manner
//
int typeClassUnqualifiedNameComparison = aTypeClassName.getUnqualifiedName().compareTo(bTypeClassName.getUnqualifiedName());
if (typeClassUnqualifiedNameComparison != 0) {
return typeClassUnqualifiedNameComparison;
} else {
/// then comparse the type classes' names in a case-sensitive manner
//
int typeClassModuleNameComparison = aTypeClassName.getModuleName().compareTo(bTypeClassName.getModuleName());
if (typeClassModuleNameComparison != 0) {
return typeClassModuleNameComparison;
} else {
/// the type classes' are in fact the same, so compare the instance type:
//
String aInstanceTypeString = a.getType().toString(ScopedEntityNamingPolicy.FULLY_QUALIFIED);
String bInstanceTypeString = b.getType().toString(ScopedEntityNamingPolicy.FULLY_QUALIFIED);
/// first compare the instance types without their constraints
//
String aInstanceTypeWithoutConstraint = aInstanceTypeString.replaceAll(".*=> ", "");
String bInstanceTypeWithoutConstraint = bInstanceTypeString.replaceAll(".*=> ", "");
int instanceTypeWithoutContraintComparison = aInstanceTypeWithoutConstraint.compareTo(bInstanceTypeWithoutConstraint);
if (instanceTypeWithoutContraintComparison != 0) {
return instanceTypeWithoutContraintComparison;
} else {
// the instance types without their constraints do not differ, so compare
// the instance types in their entirety
//
int instanceTypeComparison = aInstanceTypeString.compareTo(bInstanceTypeString);
return instanceTypeComparison;
}
}
}
}
}
/**
* A class which traverses a type signature and calculates whether the type signature contains at least one type
* constructor whose documentation is not generated.
*/
final class TypeSigCheckerForTypeConsWhereDocNotGenerated extends SourceModelTraverser<Void, Void> {
/**
* Keeps track of whether the type signature contains at least one type
* constructor whose documentation is not generated.
*/
private boolean hasTypeConsWhereDocNotGenerated = false;
/**
* @return whether the type signature contains at least one type
* constructor whose documentation is not generated.
*/
boolean hasTypeConsWhereDocNotGenerated() {
return hasTypeConsWhereDocNotGenerated;
}
/**
* Checks the type constructor being visited, and if documentation is not generated for
* it, set the member flag to indicate that there is at least one type constructor in the
* type signature visited whose documentation is not generated.
*/
@Override
public Void visit_TypeExprDefn_TypeCons(SourceModel.TypeExprDefn.TypeCons cons, Void arg) {
SourceModel.Name.TypeCons name = cons.getTypeConsName();
// NOTE: We require that the type cons name be fully qualified with a non-null module name.
if (!isDocForTypeConsGenerated(SourceModel.Name.Module.toModuleName(name.getModuleName()), name.getUnqualifiedName())) {
hasTypeConsWhereDocNotGenerated = true;
}
return super.visit_TypeExprDefn_TypeCons(cons, arg);
}
}
/**
* A class which traverses a type signature and calculates whether the type signature contains at least one type
* constructor that is not accepted (based on scope only).
*/
final class TypeSigCheckerForTypeConsNotAcceptedBasedOnScopeOnly extends SourceModelTraverser<Void, Void> {
/**
* Keeps track of whether the type signature contains at least one type
* constructor that is not accepted (based on scope only).
*/
private boolean hasTypeConsNotAcceptedBasedOnScopeOnly = false;
/**
* @return whether the type signature contains at least one type
* constructor that is not accepted (based on scope only).
*/
boolean hasTypeConsNotAcceptedBasedOnScopeOnly() {
return hasTypeConsNotAcceptedBasedOnScopeOnly;
}
/**
* Checks the type constructor being visited, and if it is not accepted,
* set the member flag to indicate that there is at least one type constructor in the
* type signature visited that is not accepted (based on scope only).
*/
@Override
public Void visit_TypeExprDefn_TypeCons(SourceModel.TypeExprDefn.TypeCons cons, Void arg) {
SourceModel.Name.TypeCons name = cons.getTypeConsName();
// NOTE: We require that the type cons name be fully qualified with a non-null module name.
if (!shouldAcceptTypeConsBasedOnScopeOnly(SourceModel.Name.Module.toModuleName(name.getModuleName()), name.getUnqualifiedName())) {
hasTypeConsNotAcceptedBasedOnScopeOnly = true;
}
return super.visit_TypeExprDefn_TypeCons(cons, arg);
}
}
/**
* A class which traverses a type signature and calculates the minimum scope of all the type
* constructors contained therein..
*/
final class MinScopeCalculatorForTypeConsInTypeSig extends SourceModelTraverser<Void, Void> {
/**
* Keeps track of the minimum scope encountered.
*/
private Scope minimumScope = Scope.PUBLIC;
/**
* @return the minimum scope encountered.
*/
Scope getMinScope() {
return minimumScope;
}
/**
* Checks the type constructor being visited, comparing its scope against the existing
* minimumScope, and setting the new minimum to be the minScope of the two.
*/
@Override
public Void visit_TypeExprDefn_TypeCons(SourceModel.TypeExprDefn.TypeCons cons, Void arg) {
SourceModel.Name.TypeCons name = cons.getTypeConsName();
if (minimumScope != Scope.PRIVATE) {
// NOTE: We require that the type cons name be fully qualified with a non-null module name.
minimumScope = minScope(minimumScope, getTypeConstructorScope(SourceModel.Name.Module.toModuleName(name.getModuleName()), name.getUnqualifiedName()));
}
return super.visit_TypeExprDefn_TypeCons(cons, arg);
}
}
/**
* Constructor for this abstract base class.
* @param programModelManager the program model manager associated with this generator.
* @param filter the filter to use for excluding modules and entries.
* @param buildUsageIndices whether to build usage indices.
* @param logger the logger for use in logging status message. Can be null.
*/
AbstractDocumentationGenerator(ProgramModelManager programModelManager, DocumentationGenerationFilter filter, boolean buildUsageIndices, Logger logger) {
verifyArg(programModelManager, "programModelManager");
this.programModelManager = programModelManager;
verifyArg(filter, "filter");
this.filter = filter;
this.shouldGenerateUsageIndices = buildUsageIndices;
if (logger == null) {
logger = Logger.getLogger(getClass().getName());
}
this.logger = logger;
this.labelMaker = new DocLabelMaker();
this.moduleIndices = new TreeMap<ModuleName, PerModuleIndices>();
this.moduleNameToDirectlyDependentModuleNames = new LinkedHashMap<ModuleName, Set<ModuleName>>();
this.moduleNameResolverForDocumentedModules = ModuleNameResolver.make(new HashSet<ModuleName>(filterModuleNames(Arrays.asList(programModelManager.getModuleNamesInProgram()))));
}
/**
* Adds a direct module dependency to our mapping of (imported module, dependent modules).
* @param importedModuleName the module that is imported.
* @param dependentModuleName the dependent module with the import statement.
*/
private void addDirectModuleDependency(ModuleName importedModuleName, ModuleName dependentModuleName) {
getDirectlyDependentModuleNames(importedModuleName).add(dependentModuleName);
}
/**
* Fetches a set of the names of the modules that import the given module.
* @param moduleName the name of the module whose direct dependents are to be returned.
* @return a Set of Strings containing the names of the directly dependent modules.
*/
Set<ModuleName> getDirectlyDependentModuleNames(ModuleName moduleName) {
Set<ModuleName> list = moduleNameToDirectlyDependentModuleNames.get(moduleName);
if (list == null) {
list = new LinkedHashSet<ModuleName>();
moduleNameToDirectlyDependentModuleNames.put(moduleName, list);
}
return list;
}
/**
* Fetches the per-module indices of the given module.
* @param moduleName the name of the module whose indices are to be returned.
* @return a PerModuleIndices instance containing the indices of the module.
*/
private PerModuleIndices getPerModuleIndices(ModuleName moduleName) {
PerModuleIndices indices = moduleIndices.get(moduleName);
if (indices == null) {
indices = new PerModuleIndices();
moduleIndices.put(moduleName, indices);
}
return indices;
}
/**
* Fetches the Type Index of the given module.
* @param moduleName the name of the module.
* @return a List of IndexEntry objects representing the index.
*/
List<IndexEntry> getPerModuleTypeIndex(ModuleName moduleName) {
return getPerModuleIndices(moduleName).typeIndex;
}
/**
* Fetches the Functional Agent Index of the given module.
* @param moduleName the name of the module.
* @return a List of IndexEntry objects representing the index.
*/
List<IndexEntry> getPerModuleFunctionalAgentIndex(ModuleName moduleName) {
return getPerModuleIndices(moduleName).functionalAgentIndex;
}
/**
* Fetches the Type Class Index of the given module.
* @param moduleName the name of the module.
* @return a List of IndexEntry objects representing the index.
*/
List<IndexEntry> getPerModuleTypeClassIndex(ModuleName moduleName) {
return getPerModuleIndices(moduleName).typeClassIndex;
}
/**
* Fetches the Instance Index of the given module.
* @param moduleName the name of the module.
* @return a List of IndexEntry objects representing the index.
*/
List<IndexEntry> getPerModuleInstanceIndex(ModuleName moduleName) {
return getPerModuleIndices(moduleName).instanceIndex;
}
/**
* Fetches the Argument Type Index of the given type constructor.
* @param usageIndices the usage indices map.
* @param qualifiedName the type constructor's name.
* @param dependentModuleName the name of the dependent's module.
* @return a TreeSet of FunctionalAgent objects whose argument types refer to the given type constructor.
*/
TreeSet<FunctionalAgent> getArgTypeIndex(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, QualifiedName qualifiedName, ModuleName dependentModuleName) {
return getArgAndReturnTypeIndices(usageIndices, qualifiedName, dependentModuleName).fst();
}
/**
* Fetches the Argument Type Index of the given type constructor.
* @param usageIndices the usage indices map.
* @param moduleName the type constructor's module name.
* @param unqualifiedName the type constructor's unqualified name.
* @param dependentModuleName the name of the dependent's module.
* @return a TreeSet of FunctionalAgent objects whose argument types refer to the given type constructor.
*/
TreeSet<FunctionalAgent> getArgTypeIndex(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, ModuleName moduleName, String unqualifiedName, ModuleName dependentModuleName) {
return getArgAndReturnTypeIndices(usageIndices, moduleName, unqualifiedName, dependentModuleName).fst();
}
/**
* Fetches the pair of Argument and Return Type Indices of the given type constructor.
* @param usageIndices the usage indices map.
* @param qualifiedName the type constructor's name.
* @param dependentModuleName the name of the dependent's module.
* @return a Pair of TreeSets of FunctionalAgent objects.
*/
private Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>> getArgAndReturnTypeIndices(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, QualifiedName qualifiedName, ModuleName dependentModuleName) {
/// First, get the right map for the given type constructor
//
Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>> theMap = usageIndices.get(qualifiedName);
if (theMap == null) {
// if there is no existing map for the type constructor, create one and add it to the usageIndices
theMap = new TreeMap<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>();
usageIndices.put(qualifiedName, theMap);
}
/// Then, get the pair of argument/return type indices for the given dependent module name
//
Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>> thePair = theMap.get(dependentModuleName);
if (thePair == null) {
// if there is no existing pair for the dependent module name, create one and add it to the map for
// the given constructor
TreeSet<FunctionalAgent> argTypeIndex = new TreeSet<FunctionalAgent>(ScopedEntityComparator.INSTANCE);
TreeSet<FunctionalAgent> returnTypeIndex = new TreeSet<FunctionalAgent>(ScopedEntityComparator.INSTANCE);
thePair = new Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>(argTypeIndex, returnTypeIndex);
theMap.put(dependentModuleName, thePair);
}
return thePair;
}
/**
* Fetches the pair of Argument and Return Type Indices of the given type constructor.
* @param usageIndices the usage indices map.
* @param moduleName the type constructor's module name.
* @param unqualifiedName the type constructor's unqualified name.
* @param dependentModuleName the name of the dependent's module.
* @return a Pair of TreeSets of FunctionalAgent objects.
*/
private Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>> getArgAndReturnTypeIndices(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, ModuleName moduleName, String unqualifiedName, ModuleName dependentModuleName) {
return getArgAndReturnTypeIndices(usageIndices, QualifiedName.make(moduleName, unqualifiedName), dependentModuleName);
}
/**
* Fetches the Return Type Index of the given type constructor.
* @param usageIndices the usage indices map.
* @param qualifiedName the type constructor's name.
* @param dependentModuleName the name of the dependent's module.
* @return a TreeSet of FunctionalAgent objects whose return types refer to the given type constructor.
*/
TreeSet<FunctionalAgent> getReturnTypeIndex(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, QualifiedName qualifiedName, ModuleName dependentModuleName) {
return getArgAndReturnTypeIndices(usageIndices, qualifiedName, dependentModuleName).snd();
}
/**
* Fetches the Return Type Index of the given type constructor.
* @param usageIndices the usage indices map.
* @param moduleName the type constructor's module name.
* @param unqualifiedName the type constructor's unqualified name.
* @param dependentModuleName the name of the dependent's module.
* @return a TreeSet of FunctionalAgent objects whose return types refer to the given type constructor.
*/
TreeSet<FunctionalAgent> getReturnTypeIndex(Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices, ModuleName moduleName, String unqualifiedName, ModuleName dependentModuleName) {
return getArgAndReturnTypeIndices(usageIndices, moduleName, unqualifiedName, dependentModuleName).snd();
}
/**
* Verifies that the argument is non-null.
* @param arg the argument to check.
* @param argName the name of the argument.
* @throws NullPointerException if the argument is null.
*/
static void verifyArg(Object arg, String argName) {
if (arg == null) {
throw new NullPointerException("The argument '" + argName + "' cannot be null.");
}
}
/**
* Takes the given entity and based on its type signature add it to the appropriate
* argument and return type indices.
* @param entity the entity to process.
*/
private void processEnvEntityForArgAndReturnTypeIndices(FunctionalAgent entity) {
if (shouldGenerateUsageIndices) {
SourceModel.TypeSignature typeSignature = entity.getTypeExpr().toSourceModel();
typeSignature.accept(new EnvEntityProcessorForArgAndReturnTypeIndices(entity), null);
}
}
/**
* This is the top-level method for generating the documentation.
*/
void generateDoc() {
// Obtain a list of all the module names
List<ModuleName> allModuleNames = Arrays.asList(programModelManager.getModuleNamesInProgram());
// Filter the list according to the user-specified configuration
List<ModuleName> moduleNames = filterModuleNames(allModuleNames);
// Sort the module names
Collections.sort(moduleNames);
////
/// Run the preparation pass through all modules, and build up the direct dependency information
//
for (int i = 0, n = moduleNames.size(); i < n; i++) {
ModuleName moduleName = moduleNames.get(i);
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
for (int j = 0, nImportedModules = moduleTypeInfo.getNImportedModules(); j < nImportedModules; j++) {
ModuleName importedModuleName = moduleTypeInfo.getNthImportedModule(j).getModuleName();
addDirectModuleDependency(importedModuleName, moduleName);
}
prepareGenerationForModule(moduleTypeInfo);
}
////
/// Run the actual documentation generation pass
//
beginDoc();
// first portion: main documentation
for (int i = 0, n = moduleNames.size(); i < n; i++) {
ModuleName moduleName = moduleNames.get(i);
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
logger.fine(CALDocMessages.getString("STATUS.generatingDocumentationForModule", moduleName));
generateModuleDoc(moduleTypeInfo);
}
// optional: usage documentation
if (shouldGenerateUsageIndices) {
for (int i = 0, n = moduleNames.size(); i < n; i++) {
ModuleName moduleName = moduleNames.get(i);
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
logger.fine(CALDocMessages.getString("STATUS.generatingUsageDocumentationForModule", moduleName));
generateUsageIndices(moduleTypeInfo);
}
}
endDoc();
}
/**
* Generates the usage indices for the given module.
* @param moduleTypeInfo the module whose type constructors are to have their usage indices generated.
*/
void generateUsageIndices(ModuleTypeInfo moduleTypeInfo) {
int nTypeConstructors = moduleTypeInfo.getNTypeConstructors();
for (int i = 0; i < nTypeConstructors; i++) {
TypeConstructor typeCons = moduleTypeInfo.getNthTypeConstructor(i);
// only generate the usage indices if the type constructor is actually to be documented
if (filter.shouldGenerateScopedEntity(typeCons)) {
beginTypeConsUsageDoc(typeCons);
generateUsageIndicesForTypeConsOrTypeClass(typeCons, typeConsUsageIndices);
endTypeConsUsageDoc(typeCons);
}
}
int nTypeClasses = moduleTypeInfo.getNTypeClasses();
for (int i = 0; i < nTypeClasses; i++) {
TypeClass typeClass = moduleTypeInfo.getNthTypeClass(i);
// only generate the usage indices if the type constructor is actually to be documented
if (filter.shouldGenerateScopedEntity(typeClass)) {
beginTypeClassUsageDoc(typeClass);
generateUsageIndicesForTypeConsOrTypeClass(typeClass, classUsageIndices);
endTypeClassUsageDoc(typeClass);
}
}
}
/**
* Generates the usage indices for a type constructor or a type class.
* @param documentedEntity the type constructor or type class whose usage is being generated.
* @param usageIndices the usage indices map.
*/
void generateUsageIndicesForTypeConsOrTypeClass(ScopedEntity documentedEntity, Map<QualifiedName, Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>>> usageIndices) {
if (!(documentedEntity instanceof TypeConstructor || documentedEntity instanceof TypeClass)) {
throw new IllegalArgumentException();
}
ModuleName moduleName = documentedEntity.getName().getModuleName();
// obtain the argument and return type indices from the usageIndices map
Map<ModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>>> theMap = usageIndices.get(documentedEntity.getName());
////
/// generate for the defining module first
//
Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>> usageIndicesForTypeConsForDefiningModule = (theMap != null) ? theMap.get(moduleName) : null;
generateUsageIndicesForDependentModule(documentedEntity, moduleName, usageIndicesForTypeConsForDefiningModule);
////
/// then generate for the other dependent modules:
//
// get a new list for the names of the directly dependent modules, so that it can be filtered and sorted later
Set<ModuleName> directlyDependentModuleNamesSet = getDirectlyDependentModuleNames(moduleName);
List<ModuleName> directlyDependentModuleNames = new ArrayList<ModuleName>(directlyDependentModuleNamesSet);
// filter the list of dependent modules
directlyDependentModuleNames = filterModuleNames(directlyDependentModuleNames);
// sort the list of dependent modules
Collections.sort(directlyDependentModuleNames);
// loop through each directly dependent module (excluding the defining module) and document the usages in each.
int nDependentModules = directlyDependentModuleNames.size();
for (int j = 0; j < nDependentModules; j++) {
ModuleName dependentModuleName = directlyDependentModuleNames.get(j);
Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>> usageIndicesForTypeCons = (theMap != null) ? theMap.get(dependentModuleName) : null;
if (!dependentModuleName.equals(moduleName)) {
generateUsageIndicesForDependentModule(documentedEntity, dependentModuleName, usageIndicesForTypeCons);
}
}
}
/**
* Generates the usage indices section for a particular dependent module.
*
* @param documentedEntity
* the ScopedEntity whose usage documentation is being
* generated.
* @param dependentModuleName
* the name of the dependent module.
* @param usageIndices
* the Pair of TreeSets of EnvEntities constituting the argument
* and return type indices affiliated with the type constructor/class
* and the dependent module. Can be null if the type constructor/class
* has neither the argument type index nor the return type index.
*/
void generateUsageIndicesForDependentModule(ScopedEntity documentedEntity, ModuleName dependentModuleName, Pair<TreeSet<FunctionalAgent>, TreeSet<FunctionalAgent>> usageIndices) {
if (!(documentedEntity instanceof TypeConstructor || documentedEntity instanceof TypeClass)) {
throw new IllegalArgumentException();
}
// obtain the list of instances
List<ClassInstance> instances = new ArrayList<ClassInstance>();
addInstancesToList(documentedEntity, dependentModuleName, instances);
int nInstances = instances.size();
// only generate the section if there is at least something in the arg/return indices or the instance index
if (usageIndices != null || nInstances > 0) {
beginUsageDocGroupForDependentModule(documentedEntity, dependentModuleName);
if (usageIndices != null) {
////
/// generate the argument type index
//
TreeSet<FunctionalAgent> argTypeIndex = usageIndices.fst();
int nArgTypeIndexEntries = argTypeIndex.size();
beginUsageDocArgTypeIndex(documentedEntity, nArgTypeIndexEntries, calcMaxScopeOfScopedEntities(argTypeIndex));
for (final FunctionalAgent entity : argTypeIndex) {
generateUsageDocArgTypeIndexEntry(documentedEntity, entity);
}
endUsageDocArgTypeIndex(documentedEntity, nArgTypeIndexEntries);
////
/// generate the return type index
//
TreeSet<FunctionalAgent> returnTypeIndex = usageIndices.snd();
int nReturnTypeIndexEntries = returnTypeIndex.size();
beginUsageDocReturnTypeIndex(documentedEntity, nReturnTypeIndexEntries, calcMaxScopeOfScopedEntities(returnTypeIndex));
for (final FunctionalAgent entity : returnTypeIndex) {
generateUsageDocReturnTypeIndexEntry(documentedEntity, entity);
}
endUsageDocReturnTypeIndex(documentedEntity, nReturnTypeIndexEntries);
}
////
/// generate the instance index
//
beginUsageDocInstanceIndex(documentedEntity, nInstances, calcMaxScopeOfClassInstances(instances));
for (int i = 0; i < nInstances; i++) {
ClassInstance instance = instances.get(i);
generateUsageDocInstanceIndexEntry(documentedEntity, instance);
}
endUsageDocInstanceIndex(documentedEntity, nInstances);
endUsageDocGroupForDependentModule(documentedEntity, dependentModuleName);
}
}
/**
* Generates the start of the type constructor usage documentation.
* @param documentedEntity the type constructor or type class whose usage is documented.
*/
abstract void beginTypeConsUsageDoc(TypeConstructor documentedEntity);
/**
* Generates the start of the type class usage documentation.
* @param documentedEntity the type constructor or type class whose usage is documented.
*/
abstract void beginTypeClassUsageDoc(TypeClass documentedEntity);
/**
* Generates the start of the usage documentation section for a particular dependent module.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param dependentModuleName the name of the dependent module.
*/
abstract void beginUsageDocGroupForDependentModule(ScopedEntity documentedEntity, ModuleName dependentModuleName);
/**
* Generates the start of an argument type index.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param nArgTypeIndexEntries the number of index entries.
* @param maxScopeOfArgTypeIndexEntries the maximum scope of the index entries.
*/
abstract void beginUsageDocArgTypeIndex(ScopedEntity documentedEntity, int nArgTypeIndexEntries, Scope maxScopeOfArgTypeIndexEntries);
/**
* Generates an argument type index entry.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param entity the functional agent entity that is the index entry.
*/
abstract void generateUsageDocArgTypeIndexEntry(ScopedEntity documentedEntity, FunctionalAgent entity);
/**
* Generates the end of an argument type index.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param nArgTypeIndexEntries the number of index entries.
*/
abstract void endUsageDocArgTypeIndex(ScopedEntity documentedEntity, int nArgTypeIndexEntries);
/**
* Generates the start of a return type index.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param nReturnTypeIndexEntries the number of index entries.
* @param maxScopeOfReturnTypeIndexEntries the maximum scope of the index entries.
*/
abstract void beginUsageDocReturnTypeIndex(ScopedEntity documentedEntity, int nReturnTypeIndexEntries, Scope maxScopeOfReturnTypeIndexEntries);
/**
* Generates a return type index entry.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param entity the functional agent entity that is the index entry.
*/
abstract void generateUsageDocReturnTypeIndexEntry(ScopedEntity documentedEntity, FunctionalAgent entity);
/**
* Generates the end of a return type index.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param nReturnTypeIndexEntries the number of index entries.
*/
abstract void endUsageDocReturnTypeIndex(ScopedEntity documentedEntity, int nReturnTypeIndexEntries);
/**
* Generates the start of an instance index as part of the usage documentation.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param nInstances the number of instances.
* @param maxScopeOfInstanceIndexEntries the maximum scope of the index entries.
*/
abstract void beginUsageDocInstanceIndex(ScopedEntity documentedEntity, int nInstances, Scope maxScopeOfInstanceIndexEntries);
/**
* Generates an instance index entry as part of the usage documentation.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param classInstance the class instance that is the index entry.
*/
abstract void generateUsageDocInstanceIndexEntry(ScopedEntity documentedEntity, ClassInstance classInstance);
/**
* Generates the end of an instance index as part of the usage documentation.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param nInstances the number of instances.
*/
abstract void endUsageDocInstanceIndex(ScopedEntity documentedEntity, int nInstances);
/**
* Generates the end of the usage documentation section for a particular dependent module.
* @param documentedEntity the type constructor or type class whose usage is documented.
* @param dependentModuleName the name of the dependent module.
*/
abstract void endUsageDocGroupForDependentModule(ScopedEntity documentedEntity, ModuleName dependentModuleName);
/**
* Generates the end of the type constructor usage documentation.
* @param documentedEntity the type constructor or type class whose usage is documented.
*/
abstract void endTypeConsUsageDoc(TypeConstructor documentedEntity);
/**
* Generates the end of the type class usage documentation.
* @param documentedEntity the type constructor or type class whose usage is documented.
*/
abstract void endTypeClassUsageDoc(TypeClass documentedEntity);
/**
* Filters the given list of module names and returns a new list containing
* only the names of those modules whose documentation are generated.
*
* @param moduleNames the list of module names to filter. This list is not modified by the filtering.
* @return the filtered list.
*/
private List<ModuleName> filterModuleNames(List<ModuleName> moduleNames) {
List<ModuleName> filteredModuleNames = new ArrayList<ModuleName>();
for (int i = 0, n = moduleNames.size(); i < n; i++) {
ModuleName moduleName = moduleNames.get(i);
if (filter.shouldGenerateModule(moduleName)) {
filteredModuleNames.add(moduleName);
}
}
return filteredModuleNames;
}
/**
* Makes the necessary preparation for later generating the documentation for the given module.
* @param moduleTypeInfo the ModuleTypeInfo of the module to prepare for.
*/
abstract void prepareGenerationForModule(ModuleTypeInfo moduleTypeInfo);
/**
* Performs the necessary task to begin the generation of documentation.
*/
abstract void beginDoc();
/**
* Performs the necessary task to end the generation of documentation.
*/
abstract void endDoc();
/**
* Generates the documentation for a module.
* @param moduleTypeInfo the ModuleTypeInfo of the module whose documentation is to be generated.
*/
void generateModuleDoc(ModuleTypeInfo moduleTypeInfo) {
ModuleName moduleName = moduleTypeInfo.getModuleName();
////
/// First, collect the various entities that need to be documented, applying the user-specified filters along the way.
//
int nTypeConstructors = moduleTypeInfo.getNTypeConstructors();
List<TypeConstructor> typeConstructorsList = new ArrayList<TypeConstructor>(nTypeConstructors);
for (int i = 0; i < nTypeConstructors; i++) {
TypeConstructor typeCons = moduleTypeInfo.getNthTypeConstructor(i);
if (filter.shouldGenerateScopedEntity(typeCons)) {
typeConstructorsList.add(typeCons);
}
}
int nFunctions = moduleTypeInfo.getNFunctions();
List<Function> functionsList = new ArrayList<Function>(nFunctions);
for (int i = 0; i < nFunctions; i++) {
Function function = moduleTypeInfo.getNthFunction(i);
if (filter.shouldGenerateScopedEntity(function)) {
functionsList.add(function);
}
}
int nTypeClasses = moduleTypeInfo.getNTypeClasses();
List<TypeClass> typeClassesList = new ArrayList<TypeClass>(nTypeClasses);
for (int i = 0; i < nTypeClasses; i++) {
TypeClass entity = moduleTypeInfo.getNthTypeClass(i);
if (filter.shouldGenerateScopedEntity(entity)) {
typeClassesList.add(entity);
}
}
int nClassInstances = moduleTypeInfo.getNClassInstances();
List<ClassInstance> classInstancesList = new ArrayList<ClassInstance>(nClassInstances);
for (int i = 0; i < nClassInstances; i++) {
ClassInstance classInstance = moduleTypeInfo.getNthClassInstance(i);
if (isDocForClassInstanceGenerated(classInstance)) {
classInstancesList.add(classInstance);
}
}
////
/// Sort the entities with the appropriate comparator, so that the documentation can generated in an easy-to-understand order.
//
Collections.sort(typeConstructorsList, ScopedEntityComparator.INSTANCE);
Collections.sort(functionsList, ScopedEntityComparator.INSTANCE);
Collections.sort(typeClassesList, ScopedEntityComparator.INSTANCE);
Collections.sort(classInstancesList, new ClassInstanceComparator());
TypeConstructor[] typeConstructors = typeConstructorsList.toArray(new TypeConstructor[0]);
Function[] functions = functionsList.toArray(new Function[0]);
TypeClass[] typeClasses = typeClassesList.toArray(new TypeClass[0]);
ClassInstance[] classInstances = classInstancesList.toArray(new ClassInstance[0]);
////
/// Actually generate the documentation.
//
beginModuleDoc(moduleTypeInfo, typeConstructors.length, functions.length, typeClasses.length, classInstances.length);
generateModuleHeaderSection(moduleTypeInfo);
generateModuleOverviewSection(typeConstructors, functions, typeClasses, classInstances);
generateModuleDetailsSection(moduleName, typeConstructors, functions, typeClasses, classInstances);
endModuleDoc(typeConstructors.length, functions.length, typeClasses.length, classInstances.length);
}
/**
* Generates the start of the documentation for a module.
* @param moduleTypeInfo the ModuleTypeInfo of the module.
* @param nTypeConstructors the number of type constructors to be documented (not necessarily equal to the number of all type constructors in the module).
* @param nFunctions the number of functions to be documented (not necessarily equal to the number of all functions in the module).
* @param nTypeClasses the number of type classes to be documented (not necessarily equal to the number of all type classes in the module).
* @param nClassInstances the number of class instances to be documented (not necessarily equal to the number of all class instances in the module).
*/
abstract void beginModuleDoc(ModuleTypeInfo moduleTypeInfo, int nTypeConstructors, int nFunctions, int nTypeClasses, int nClassInstances);
/**
* Generates the end of the documentation for a module.
* @param nTypeConstructors the number of type constructors to be documented (not necessarily equal to the number of all type constructors in the module).
* @param nFunctions the number of functions to be documented (not necessarily equal to the number of all functions in the module).
* @param nTypeClasses the number of type classes to be documented (not necessarily equal to the number of all type classes in the module).
* @param nClassInstances the number of class instances to be documented (not necessarily equal to the number of all class instances in the module).
*/
abstract void endModuleDoc(int nTypeConstructors, int nFunctions, int nTypeClasses, int nClassInstances);
/**
* Generates the header section of the documentation for a module.
* @param moduleTypeInfo the ModuleTypeInfo of the module.
*/
void generateModuleHeaderSection(ModuleTypeInfo moduleTypeInfo) {
ModuleName moduleName = moduleTypeInfo.getModuleName();
generateModuleDescription(moduleTypeInfo);
////
/// Generate the list of imported modules
//
// note: we don't filter out the modules for which documentation is not generated,
// since it would be misleading to say that a module A imports no modules (not
// even Prelude) if it is the only module whose documentation is generated,
// when in fact it imports Prelude and also some other modules B, C, D.
int nImportedModules = moduleTypeInfo.getNImportedModules();
beginImportedModulesList(nImportedModules);
for (int i = 0; i < nImportedModules; i++) {
generateImportedModule(moduleTypeInfo.getNthImportedModule(i), i, nImportedModules);
}
endImportedModulesList(nImportedModules);
////
/// Generate the list of friend modules
//
// note: we don't filter out the modules for which documentation is not generated,
// since friend modules are granted special privileges (to access protected entities)
// and it would be good to know the entire set of modules which are granted these privileges
// whether they are included in the documentation or not.
int nFriendModules = moduleTypeInfo.getNFriendModules();
beginFriendModulesList(nFriendModules);
for (int i = 0; i < nFriendModules; i++) {
generateFriendModule(moduleTypeInfo.getNthFriendModule(i), i, nFriendModules);
}
endFriendModulesList(nFriendModules);
////
/// Generate the list of directly dependent modules
//
Set<ModuleName> directlyDependentModuleNamesSet = getDirectlyDependentModuleNames(moduleName);
List<ModuleName> directlyDependentModuleNames = new ArrayList<ModuleName>(directlyDependentModuleNamesSet);
// filter the list of dependent modules
directlyDependentModuleNames = filterModuleNames(directlyDependentModuleNames);
// sort the list of dependent modules in lexicographical order
Collections.sort(directlyDependentModuleNames);
int nDirectlyDependentModules = directlyDependentModuleNames.size();
beginDirectlyDependentModulesList(nDirectlyDependentModules);
for (int i = 0; i < nDirectlyDependentModules; i++) {
generateDirectlyDependentModule(directlyDependentModuleNames.get(i), i, nDirectlyDependentModules);
}
endDirectlyDependentModulesList(nDirectlyDependentModules);
////
/// Generate the list of indirectly dependent modules
//
List<ModuleName> indirectlyDependentModulesList = new ArrayList<ModuleName>();
for (final ModuleName dependentModuleName : programModelManager.getDependentModuleNames(moduleName)) {
if (!directlyDependentModuleNamesSet.contains(dependentModuleName)) {
indirectlyDependentModulesList.add(dependentModuleName);
}
}
// filter the list of dependent modules
indirectlyDependentModulesList = filterModuleNames(indirectlyDependentModulesList);
// sort the list of dependent modules in lexicographical order
Collections.sort(indirectlyDependentModulesList);
int nIndirectlyDependentModules = indirectlyDependentModulesList.size();
beginIndirectlyDependentModulesList(nIndirectlyDependentModules);
for (int i = 0; i < nIndirectlyDependentModules; i++) {
generateIndirectlyDependentModule(indirectlyDependentModulesList.get(i), i, nIndirectlyDependentModules);
}
endIndirectlyDependentModulesList(nIndirectlyDependentModules);
}
/**
* Generates the start of the imported modules list.
* @param nImportedModules the number of imported modules.
*/
abstract void beginImportedModulesList(int nImportedModules);
/**
* Generates an imported modules list entry.
* @param moduleTypeInfo the ModuleTypeInfo of the imported module.
* @param index the position of this entry in its enclosing list.
* @param nImportedModules the number of entries in the list.
*/
abstract void generateImportedModule(ModuleTypeInfo moduleTypeInfo, int index, int nImportedModules);
/**
* Generates the end of the imported modules list.
* @param nImportedModules the number of imported modules.
*/
abstract void endImportedModulesList(int nImportedModules);
/**
* Generates the start of the friend modules list.
* @param nFriendModules the number of friend modules.
*/
abstract void beginFriendModulesList(int nFriendModules);
/**
* Generates an friend modules list entry.
* @param moduleName the name of the friend module.
* @param index the position of this entry in its enclosing list.
* @param nFriendModules the number of entries in the list.
*/
abstract void generateFriendModule(ModuleName moduleName, int index, int nFriendModules);
/**
* Generates the end of the friend modules list.
* @param nFriendModules the number of friend modules.
*/
abstract void endFriendModulesList(int nFriendModules);
/**
* Generates the start of the directly dependent modules list.
* @param nDependentModules the number of dependent modules.
*/
abstract void beginDirectlyDependentModulesList(int nDependentModules);
/**
* Generates a directly dependent modules list entry.
* @param moduleName the name of the dependent module.
* @param index the position of this entry in its enclosing list.
* @param nDependentModules the number of entries in the list.
*/
abstract void generateDirectlyDependentModule(ModuleName moduleName, int index, int nDependentModules);
/**
* Generates the end of the directly dependent modules list.
* @param nDependentModules the number of dependent modules.
*/
abstract void endDirectlyDependentModulesList(int nDependentModules);
/**
* Generates the start of the indirectly dependent modules list.
* @param nDependentModules the number of dependent modules.
*/
abstract void beginIndirectlyDependentModulesList(int nDependentModules);
/**
* Generates an indirectly dependent modules list entry.
* @param moduleName the name of the dependent module.
* @param index the position of this entry in its enclosing list.
* @param nDependentModules the number of entries in the list.
*/
abstract void generateIndirectlyDependentModule(ModuleName moduleName, int index, int nDependentModules);
/**
* Generates the end of the indirectly dependent modules list.
* @param nDependentModules the number of dependent modules.
*/
abstract void endIndirectlyDependentModulesList(int nDependentModules);
/**
* Generates the description of the given module.
* @param moduleTypeInfo the ModuleTypeInfo of the module.
*/
abstract void generateModuleDescription(ModuleTypeInfo moduleTypeInfo);
/**
* Generates the overview section of the documentation for the given module.
* @param typeConstructors the array of type constructors to be documented.
* @param functions the array of functions to be documented.
* @param typeClasses the array of type classes to be documented.
* @param classInstances the array of class instances to be documented.
*/
void generateModuleOverviewSection(TypeConstructor[] typeConstructors, Function[] functions, TypeClass[] typeClasses, ClassInstance[] classInstances) {
int nTypeConstructors = typeConstructors.length;
int nFunctions = functions.length;
int nTypeClasses = typeClasses.length;
int nClassInstances = classInstances.length;
// determine whether the entire overview section is empty
boolean isOverviewSectionEmpty = (nTypeConstructors == 0) && (nFunctions == 0) && (nTypeClasses == 0) && (nClassInstances == 0);
beginModuleOverviewSection(isOverviewSectionEmpty);
////
/// generate the type constructor section of the overview
//
beginTypeConsOverviewSection(nTypeConstructors, calcMaxScopeOfScopedEntities(typeConstructors));
for (int i = 0; i < nTypeConstructors; i++) {
generateTypeConsOverview(typeConstructors[i]);
}
endTypeConsOverviewSection(nTypeConstructors);
////
/// generate the functions section of the overview
//
beginFunctionsOverviewSection(nFunctions, calcMaxScopeOfScopedEntities(functions));
for (int i = 0; i < nFunctions; i++) {
generateFunctionOverview(functions[i]);
}
endFunctionsOverviewSection(nFunctions);
////
/// generate the type class section of the overview
//
beginTypeClassOverviewSection(nTypeClasses, calcMaxScopeOfScopedEntities(typeClasses));
for (int i = 0; i < nTypeClasses; i++) {
generateTypeClassOverview(typeClasses[i]);
}
endTypeClassOverviewSection(nTypeClasses);
////
/// generate the class instances section of the overview
//
beginClassInstancesOverviewSection(nClassInstances, calcMaxScopeOfClassInstances(classInstances));
for (int i = 0; i < nClassInstances; i++) {
generateClassInstanceOverview(classInstances[i]);
}
endClassInstancesOverviewSection(nClassInstances);
endModuleOverviewSection(isOverviewSectionEmpty);
}
/**
* Generates the start of the module overview portion of the documentation.
* @param isOverviewSectionEmpty whether the section is actually empty.
*/
abstract void beginModuleOverviewSection(boolean isOverviewSectionEmpty);
/**
* Generates the end of the module overview portion of the documentation.
* @param isOverviewSectionEmpty whether the section is actually empty.
*/
abstract void endModuleOverviewSection(boolean isOverviewSectionEmpty);
/**
* Generates the start of the type constructors section of the module overview.
* @param nTypeConstructors the number of type constructors to be documented.
* @param maxScopeOfTypeConstructors the maximum scope of the type constructors.
*/
abstract void beginTypeConsOverviewSection(int nTypeConstructors, Scope maxScopeOfTypeConstructors);
/**
* Generates the end of the type constructors section of the module overview.
* @param nTypeConstructors the number of type constructors to be documented.
*/
abstract void endTypeConsOverviewSection(int nTypeConstructors);
/**
* Generates the start of the functions section of the module overview.
* @param nFunctions the number of functions to be documented.
* @param maxScopeOfFunctions the maximum scope of the functions.
*/
abstract void beginFunctionsOverviewSection(int nFunctions, Scope maxScopeOfFunctions);
/**
* Generates the end of the functions section of the module overview.
* @param nFunctions the number of functions to be documented.
*/
abstract void endFunctionsOverviewSection(int nFunctions);
/**
* Generates the start of the type classes section of the module overview.
* @param nTypeClasses the number of type classes to be documented.
* @param maxScopeOfTypeClasses the maximum scope of the type classes.
*/
abstract void beginTypeClassOverviewSection(int nTypeClasses, Scope maxScopeOfTypeClasses);
/**
* Generates the end of the type classes section of the module overview.
* @param nTypeClasses the number of type classes to be documented.
*/
abstract void endTypeClassOverviewSection(int nTypeClasses);
/**
* Generates the start of the class instances section of the module overview.
* @param nClassInstances the number of class instances to be documented.
* @param maxScopeOfClassInstances the maximum scope of the class instances.
*/
abstract void beginClassInstancesOverviewSection(int nClassInstances, Scope maxScopeOfClassInstances);
/**
* Generates the end of the class instances section of the module overview.
* @param nClassInstances the number of class instances to be documented.
*/
abstract void endClassInstancesOverviewSection(int nClassInstances);
/**
* Generates an overview entry for a type constructor.
* @param typeConstructor the type constructor to be documented.
*/
void generateTypeConsOverview(TypeConstructor typeConstructor) {
////
/// Generate information about the type constructor itself
//
generateTypeConsOverviewHeader(typeConstructor);
////
/// Create a list of the data constructors to be documented, applying the user-specified filters along the way.
//
int nDataConstructors = typeConstructor.getNDataConstructors();
List<DataConstructor> dataConstructorsList = new ArrayList<DataConstructor>(nDataConstructors);
for (int i = 0; i < nDataConstructors; i++) {
DataConstructor entity = typeConstructor.getNthDataConstructor(i);
if (filter.shouldGenerateScopedEntity(entity)) {
dataConstructorsList.add(entity);
}
}
////
/// Generate the list of data constructors
//
int nDataConstructorsToGenerate = dataConstructorsList.size();
beginDataConsOverviewList(nDataConstructorsToGenerate, calcMaxScopeOfScopedEntities(dataConstructorsList));
for (int i = 0; i < nDataConstructorsToGenerate; i++) {
generateDataConsOverview(dataConstructorsList.get(i));
}
endDataConsOverviewList(nDataConstructorsToGenerate);
generateTypeConsOverviewFooter();
}
/**
* Generates the header portion of the overview entry for a type constructor.
* @param typeConstructor the type constructor to be documented.
*/
abstract void generateTypeConsOverviewHeader(TypeConstructor typeConstructor);
/**
* Generates the start of the list of data constructors for the overview entry for a type constructor.
* @param nDataConstructors the number of data constructors to be documented.
* @param maxScopeOfDataConstructors the maximum scope of the data constructors.
*/
abstract void beginDataConsOverviewList(int nDataConstructors, Scope maxScopeOfDataConstructors);
/**
* Generates an overview entry for a data constructor.
* @param dataConstructor the data constructor to be documented.
*/
abstract void generateDataConsOverview(DataConstructor dataConstructor);
/**
* Generates the end of the list of data constructors for the overview entry for a type constructor.
* @param nDataConstructors the number of data constructors to be documented.
*/
abstract void endDataConsOverviewList(int nDataConstructors);
/**
* Generates the footer portion of the overview entry for a type constructor.
*/
abstract void generateTypeConsOverviewFooter();
/**
* Generates an overview entry for a function.
* @param function the function to be documented.
*/
abstract void generateFunctionOverview(Function function);
/**
* Generates an overview entry for a type class.
* @param typeClass the type class to be documented.
*/
void generateTypeClassOverview(TypeClass typeClass) {
////
/// Generate information about the type class itself
//
generateTypeClassOverviewHeader(typeClass);
////
/// Create a list of the class methods to be documented, applying the user-specified filters along the way.
//
int nClassMethods = typeClass.getNClassMethods();
List<ClassMethod> classMethodsList = new ArrayList<ClassMethod>(nClassMethods);
for (int i = 0; i < nClassMethods; i++) {
ClassMethod entity = typeClass.getNthClassMethod(i);
if (filter.shouldGenerateScopedEntity(entity)) {
classMethodsList.add(entity);
}
}
////
/// Generate the list of class methods
//
int nClassMethodsToGenerate = classMethodsList.size();
beginClassMethodOverviewList(nClassMethodsToGenerate);
for (int i = 0; i < nClassMethodsToGenerate; i++) {
generateClassMethodOverview(classMethodsList.get(i));
}
endClassMethodOverviewList(nClassMethodsToGenerate);
generateTypeClassOverviewFooter();
}
/**
* Generates the header portion of the overview entry for a type class.
* @param typeClass the type class to be documented.
*/
abstract void generateTypeClassOverviewHeader(TypeClass typeClass);
/**
* Generates the start of the list of class methods for the overview entry for a type class.
* @param nClassMethods the number of class methods to be documented.
*/
abstract void beginClassMethodOverviewList(int nClassMethods);
/**
* Generates an overview entry for a class method.
* @param classMethod the class method to be documented.
*/
abstract void generateClassMethodOverview(ClassMethod classMethod);
/**
* Generates the end of the list of class methods for the overview entry for a type class.
* @param nClassMethods the number of class methods to be documented.
*/
abstract void endClassMethodOverviewList(int nClassMethods);
/**
* Generates the footer portion of the overview entry for a type class.
*/
abstract void generateTypeClassOverviewFooter();
/**
* Generates an overview entry for a class instance.
* @param classInstance the class instances to be documented.
*/
void generateClassInstanceOverview(ClassInstance classInstance) {
////
/// Generate information about the class instance itself
//
generateClassInstanceOverviewHeader(classInstance);
////
/// Generate the list of instance methods
/// (no filtering necessary: if the class instance is to be generated, then so should all its methods)
//
int nInstanceMethods = classInstance.getNInstanceMethods();
beginInstanceMethodOverviewList(nInstanceMethods);
TypeClass typeClass = classInstance.getTypeClass();
for (int i = 0; i < nInstanceMethods; i++) {
generateInstanceMethodOverview(classInstance, typeClass.getNthClassMethod(i).getName().getUnqualifiedName());
}
endInstanceMethodOverviewList(nInstanceMethods);
generateClassInstanceOverviewFooter();
}
/**
* Generates the header portion of the overview entry for a class instance.
* @param classInstance the class instance to be documented.
*/
abstract void generateClassInstanceOverviewHeader(ClassInstance classInstance);
/**
* Generates the start of the list of instance methods for the overview entry for a class instance.
* @param nInstanceMethods the number of instance methods to be documented.
*/
abstract void beginInstanceMethodOverviewList(int nInstanceMethods);
/**
* Generates an overview entry for an instance method.
* @param classInstance the class instance of the instance method.
* @param methodName the name of the method.
*/
abstract void generateInstanceMethodOverview(ClassInstance classInstance, String methodName);
/**
* Generates the end of the list of instance methods for the overview entry for a class instance.
* @param nInstanceMethods the number of instance methods to be documented.
*/
abstract void endInstanceMethodOverviewList(int nInstanceMethods);
/**
* Generates the footer portion of the overview entry for a class instance.
*/
abstract void generateClassInstanceOverviewFooter();
/**
* Generates the details section of the documentation for a module.
* @param moduleName the name of the module.
* @param typeConstructors the array of type constructors to be documented.
* @param functions the array of functions to be documented.
* @param typeClasses the array of type classes to be documented.
* @param classInstances the array of class instances to be documented.
*/
void generateModuleDetailsSection(ModuleName moduleName, TypeConstructor[] typeConstructors, Function[] functions, TypeClass[] typeClasses, ClassInstance[] classInstances) {
generateTypeConsDocSection(moduleName, typeConstructors);
generateFunctionsDocSection(moduleName, functions);
generateTypeClassesDocSection(moduleName, typeClasses);
generateClassInstancesDocSection(moduleName, classInstances);
}
/**
* Generates the type constructors portion of the detailed documentation.
* @param moduleName the name of the module.
* @param typeConstructors the array of type cnostructors to be documented.
*/
void generateTypeConsDocSection(ModuleName moduleName, TypeConstructor[] typeConstructors) {
List<IndexEntry> perModuleTypeIndex = getPerModuleTypeIndex(moduleName);
////
/// Generate the documentation for each type constructor, and add each to the main index.
//
int nTypeConstructors = typeConstructors.length;
beginTypeConsDocSection(nTypeConstructors, calcMaxScopeOfScopedEntities(typeConstructors));
for (int i = 0; i < nTypeConstructors; i++) {
TypeConstructor typeConstructor = typeConstructors[i];
QualifiedName name = typeConstructor.getName();
perModuleTypeIndex.add(new IndexEntry(name.getUnqualifiedName(), labelMaker.getLabel(typeConstructor), typeConstructor.getScope(), IndexEntry.Kind.TYPE));
generateTypeConsDoc(typeConstructor, i);
}
endTypeConsDocSection(nTypeConstructors);
}
/**
* Generates the functions portion of the detailed documentation.
* @param moduleName the name of the module.
* @param functions the array of functions to be documented.
*/
void generateFunctionsDocSection(ModuleName moduleName, Function[] functions) {
List<IndexEntry> perModuleFunctionalAgentIndex = getPerModuleFunctionalAgentIndex(moduleName);
////
/// Generate the documentation for each type constructor, and add each to the main index
/// and the argument type and return type indices.
//
int nFunctions = functions.length;
beginFunctionsDocSection(nFunctions, calcMaxScopeOfScopedEntities(functions));
for (int i = 0; i < nFunctions; i++) {
Function function = functions[i];
QualifiedName name = function.getName();
perModuleFunctionalAgentIndex.add(new IndexEntry(name.getUnqualifiedName(), labelMaker.getLabel(function), function.getScope(), IndexEntry.Kind.FUNCTIONAL_AGENT));
processEnvEntityForArgAndReturnTypeIndices(function);
generateFunctionDoc(function, i);
}
endFunctionsDocSection(nFunctions);
}
/**
* Generates the type classes portion of the detailed documentation.
* @param moduleName the name of the module.
* @param typeClasses the array of type classes to be documented.
*/
void generateTypeClassesDocSection(ModuleName moduleName, TypeClass[] typeClasses) {
List<IndexEntry> perModuleClassIndex = getPerModuleTypeClassIndex(moduleName);
////
/// Generate the documentation for each type class, and add each to the main index.
//
int nTypeClasses = typeClasses.length;
beginTypeClassesDocSection(nTypeClasses, calcMaxScopeOfScopedEntities(typeClasses));
for (int i = 0; i < nTypeClasses; i++) {
TypeClass typeClass = typeClasses[i];
QualifiedName name = typeClass.getName();
perModuleClassIndex.add(new IndexEntry(name.getUnqualifiedName(), labelMaker.getLabel(typeClass), typeClass.getScope(), IndexEntry.Kind.TYPE_CLASS));
generateTypeClassDoc(typeClass, i);
}
endTypeClassesDocSection(nTypeClasses);
}
/**
* Generates the class instances portion of the detailed documentation.
* @param moduleName the name of the module.
* @param classInstances the array of class instances to be documented.
*/
void generateClassInstancesDocSection(ModuleName moduleName, ClassInstance[] classInstances) {
List<IndexEntry> perModuleInstanceIndex = getPerModuleInstanceIndex(moduleName);
////
/// Generate the documentation for each class instance, and add each to the main index.
//
int nClassInstances = classInstances.length;
beginClassInstancesDocSection(nClassInstances, classInstances, calcMaxScopeOfClassInstances(classInstances));
for (int i = 0; i < nClassInstances; i++) {
ClassInstance classInstance = classInstances[i];
perModuleInstanceIndex.add(new IndexEntry(getClassInstanceDisplayName(classInstance), labelMaker.getLabel(classInstance), minScopeForInstanceClassAndInstanceType(classInstance), IndexEntry.Kind.INSTANCE));
generateClassInstanceDoc(classInstance, i);
}
endClassInstancesDocSection(nClassInstances);
}
/**
* Returns the display name for a class instance.
* @param classInstance the class instance.
* @return the display name for the class instance.
*/
String getClassInstanceDisplayName(ClassInstance classInstance) {
return classInstance.getNameWithContext(ScopedEntityNamingPolicy.UNQUALIFIED);
}
/**
* Generates the start of the type constructor section of the detailed documentation.
* @param nTypeConstructors the number of type constructors to be documented.
* @param maxScopeOfTypeConstructors the maximum scope of the type constructors.
*/
abstract void beginTypeConsDocSection(int nTypeConstructors, Scope maxScopeOfTypeConstructors);
/**
* Generates the detailed documentation for a type constructor.
* @param typeConstructor the type constructor to be documented.
* @param index the position of this entry in its enclosing list.
*/
void generateTypeConsDoc(TypeConstructor typeConstructor, int index) {
////
/// Generate documentation about the type constructor itself.
//
generateTypeConsDocHeader(typeConstructor, index);
////
/// Create a list of the data constructors to be documented, applying the user-specified filters along the way.
//
int nDataConstructors = typeConstructor.getNDataConstructors();
List<DataConstructor> dataConstructorsList = new ArrayList<DataConstructor>(nDataConstructors);
for (int i = 0; i < nDataConstructors; i++) {
DataConstructor entity = typeConstructor.getNthDataConstructor(i);
if (filter.shouldGenerateScopedEntity(entity)) {
dataConstructorsList.add(entity);
}
}
ModuleName moduleName = typeConstructor.getName().getModuleName();
////
/// Generate documentation for each data constructor of this type constructor, and add each to the main index
/// and the argument type and return type indices.
//
List<IndexEntry> perModuleFunctionalAgentIndex = getPerModuleFunctionalAgentIndex(moduleName);
int nDataConstructorsToGenerate = dataConstructorsList.size();
beginDataConsDocList(nDataConstructorsToGenerate, calcMaxScopeOfScopedEntities(dataConstructorsList));
for (int i = 0; i < nDataConstructorsToGenerate; i++) {
DataConstructor dataConstructor = dataConstructorsList.get(i);
QualifiedName name = dataConstructor.getName();
perModuleFunctionalAgentIndex.add(new IndexEntry(name.getUnqualifiedName(), labelMaker.getLabel(dataConstructor), dataConstructor.getScope(), IndexEntry.Kind.FUNCTIONAL_AGENT));
processEnvEntityForArgAndReturnTypeIndices(dataConstructor);
generateDataConsDoc(dataConstructor, i);
}
endDataConsDocList(nDataConstructorsToGenerate);
////
/// Identify the known instances of this type constructor.
//
Set<ModuleName> namesOfModulesToSearchForInstances = getDirectlyDependentModuleNames(moduleName);
namesOfModulesToSearchForInstances.add(moduleName);
List<ClassInstance> knownInstances = new ArrayList<ClassInstance>();
for (final ModuleName nameOfModuleToSearchForInstances : namesOfModulesToSearchForInstances) {
addInstancesToList(typeConstructor, nameOfModuleToSearchForInstances, knownInstances);
}
// sort the known instances according to the standard order
Collections.sort(knownInstances, new ClassInstanceComparator());
////
/// Generate references to known instances of this type constructor.
//
int nKnownInstances = knownInstances.size();
beginKnownInstancesList(nKnownInstances, calcMaxScopeOfClassInstances(knownInstances));
for (int i = 0; i < nKnownInstances; i++) {
generateKnownInstance(knownInstances.get(i), i);
}
endKnownInstancesList(nKnownInstances);
generateTypeConsDocFooter(typeConstructor, index);
}
/**
* Add the instances for the specified type constructor or type class found in the specified module into the given list.
* @param documentedEntity the type constructor or type class whose instances are to be returned.
* @param nameOfModuleToSearchForInstances the module in which to search for instances.
* @param instances the List to which instances are to be added.
*/
private void addInstancesToList(ScopedEntity documentedEntity, ModuleName nameOfModuleToSearchForInstances, List<ClassInstance> instances) {
if (documentedEntity instanceof TypeConstructor) {
addInstancesOfTypeConsToList((TypeConstructor)documentedEntity, nameOfModuleToSearchForInstances, instances);
} else if (documentedEntity instanceof TypeClass) {
addIntancesOfTypeClassToList((TypeClass)documentedEntity, nameOfModuleToSearchForInstances, instances);
} else {
throw new IllegalArgumentException();
}
}
/**
* Add the instances for the specified type constructor found in the specified module into the given list.
* @param typeConstructor the type constructor whose instances are to be returned.
* @param nameOfModuleToSearchForInstances the module in which to search for instances.
* @param instances the List to which instances are to be added.
*/
private void addInstancesOfTypeConsToList(TypeConstructor typeConstructor, ModuleName nameOfModuleToSearchForInstances, List<ClassInstance> instances) {
ModuleTypeInfo moduleToSearchForInstances = programModelManager.getModuleTypeInfo(nameOfModuleToSearchForInstances);
int nClassInstances = moduleToSearchForInstances.getNClassInstances();
for (int i = 0; i < nClassInstances; i++) {
ClassInstance classInstance = moduleToSearchForInstances.getNthClassInstance(i);
if (classInstance.isTypeConstructorInstance()) {
ClassInstanceIdentifier.TypeConstructorInstance identifier =
(ClassInstanceIdentifier.TypeConstructorInstance)classInstance.getIdentifier();
////
/// Only add the instance to the list of know instances if both the type class
/// and the type constructors in the instance type have their documentation generated.
//
if (identifier.getTypeConsName().equals(typeConstructor.getName()) &&
isDocForClassInstanceGenerated(classInstance)) {
instances.add(classInstance);
}
}
}
}
/**
* Add the instances for the specified type class found in the specified module into the given list.
* @param typeClass the type class whose instances are to be returned.
* @param nameOfModuleToSearchForInstances the module in which to search for instances.
* @param instances the List to which instances are to be added.
*/
private void addIntancesOfTypeClassToList(TypeClass typeClass, ModuleName nameOfModuleToSearchForInstances, List<ClassInstance> instances) {
ModuleTypeInfo moduleToSearchForInstances = programModelManager.getModuleTypeInfo(nameOfModuleToSearchForInstances);
int nClassInstances = moduleToSearchForInstances.getNClassInstances();
for (int i = 0; i < nClassInstances; i++) {
ClassInstance classInstance = moduleToSearchForInstances.getNthClassInstance(i);
////
/// Only add the instance to the list of know instances if both the type class
/// and the type constructors in the instance type have their documentation generated.
//
if (classInstance.getTypeClass().getName().equals(typeClass.getName()) &&
isDocForClassInstanceGenerated(classInstance)) {
instances.add(classInstance);
}
}
}
/**
* Generate the header portion of the detailed documentation for a type constructor.
* @param typeConstructor the type constructor to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateTypeConsDocHeader(TypeConstructor typeConstructor, int index);
/**
* Generates the start of the list of data constructors for the detailed documentation for a type constructor.
* @param nDataConstructors the number of data constructors to be documented.
* @param maxScopeOfDataConstructors the maximum scope of the data constructors.
*/
abstract void beginDataConsDocList(int nDataConstructors, Scope maxScopeOfDataConstructors);
/**
* Generates the detailed documentation for a data constructor.
* @param dataConstructor the data constructor to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateDataConsDoc(DataConstructor dataConstructor, int index);
/**
* Generates the end of the list of data constructors for the detailed documentation for a type constructor.
* @param nDataConstructors the number of data constructors to be documented.
*/
abstract void endDataConsDocList(int nDataConstructors);
/**
* Generate the footer portion of the detailed documentation for a type constructor.
* @param typeConstructor the type constructor to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateTypeConsDocFooter(TypeConstructor typeConstructor, int index);
/**
* Generates the end of the type constructor section of the detailed documentation.
* @param nTypeConstructors the number of type constructors to be documented.
*/
abstract void endTypeConsDocSection(int nTypeConstructors);
/**
* Generates the start of the functions section of the detailed documentation.
* @param nFunctions the number of functions to be documented.
* @param maxScopeOfFunctions the maximum scope of the functions.
*/
abstract void beginFunctionsDocSection(int nFunctions, Scope maxScopeOfFunctions);
/**
* Generates the detailed documentation for a function.
* @param function the function to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateFunctionDoc(Function function, int index);
/**
* Generates the end of the functions section of the detailed documentation.
* @param nFunctions the number of functions to be documented.
*/
abstract void endFunctionsDocSection(int nFunctions);
/**
* Generates the start of the type class section of the detailed documentation.
* @param nTypeClasses the number of type classes to be documented.
* @param maxScopeOfTypeClasses the maximum scope of the type classes.
*/
abstract void beginTypeClassesDocSection(int nTypeClasses, Scope maxScopeOfTypeClasses);
/**
* Generates the detailed documentation for a type class.
* @param typeClass the type class to be documented.
* @param index the position of this entry in its enclosing list.
*/
void generateTypeClassDoc(TypeClass typeClass, int index) {
////
/// Generate documentation about the type class itself.
//
generateTypeClassDocHeader(typeClass, index);
////
/// Create a list of the type classes to be documented, applying the user-specified filters along the way.
//
int nClassMethods = typeClass.getNClassMethods();
List<ClassMethod> classMethodsList = new ArrayList<ClassMethod>(nClassMethods);
for (int i = 0; i < nClassMethods; i++) {
ClassMethod entity = typeClass.getNthClassMethod(i);
if (filter.shouldGenerateScopedEntity(entity)) {
classMethodsList.add(entity);
}
}
ModuleName moduleName = typeClass.getName().getModuleName();
////
/// Generate documentation for each method of this class, and add each to the main index
/// and the argument type and return type indices.
//
List<IndexEntry> perModuleFunctionalAgentIndex = getPerModuleFunctionalAgentIndex(moduleName);
int nClassMethodsToGenerate = classMethodsList.size();
beginClassMethodDocList(nClassMethodsToGenerate);
for (int i = 0; i < nClassMethodsToGenerate; i++) {
ClassMethod classMethod = classMethodsList.get(i);
QualifiedName classMethodName = classMethod.getName();
perModuleFunctionalAgentIndex.add(new IndexEntry(classMethodName.getUnqualifiedName(), labelMaker.getLabel(classMethod), classMethod.getScope(), IndexEntry.Kind.FUNCTIONAL_AGENT));
processEnvEntityForArgAndReturnTypeIndices(classMethod);
generateClassMethodDoc(classMethod, i);
}
endClassMethodDocList(nClassMethodsToGenerate);
////
/// Identify the known instances of this class.
//
Set<ModuleName> namesOfModulesToSearchForInstances = getDirectlyDependentModuleNames(moduleName);
namesOfModulesToSearchForInstances.add(moduleName);
List<ClassInstance> knownInstances = new ArrayList<ClassInstance>();
for (final ModuleName nameOfModuleToSearchForInstances : namesOfModulesToSearchForInstances) {
addIntancesOfTypeClassToList(typeClass, nameOfModuleToSearchForInstances, knownInstances);
}
// sort the known instances according to the standard order
Collections.sort(knownInstances, new ClassInstanceComparator());
////
/// Generate references to known instances of this class.
//
int nKnownInstances = knownInstances.size();
beginKnownInstancesList(nKnownInstances, calcMaxScopeOfClassInstances(knownInstances));
for (int i = 0; i < nKnownInstances; i++) {
generateKnownInstance(knownInstances.get(i), i);
}
endKnownInstancesList(nKnownInstances);
generateTypeClassDocFooter(typeClass, index);
}
/**
* Generates the header portion of the detailed documentation for a type class.
* @param typeClass the type class to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateTypeClassDocHeader(TypeClass typeClass, int index);
/**
* Generates the start of the list of class methods for the detailed documentation for a type class.
* @param nClassMethods the number of class methods to be documented.
*/
abstract void beginClassMethodDocList(int nClassMethods);
/**
* Generates the detailed documentation for a class method.
* @param classMethod the class method to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateClassMethodDoc(ClassMethod classMethod, int index);
/**
* Generates the end of the list of class methods for the detailed documentation for a type class.
* @param nClassMethods the number of class methods to be documented.
*/
abstract void endClassMethodDocList(int nClassMethods);
/**
* Generates the start of the list of known instances for the detailed documentation for a type constructor or type class.
* @param nKnownInstances the number of known instances to be documented.
* @param maxScopeOfKnownInstances the maximum scope of the known instances.
*/
abstract void beginKnownInstancesList(int nKnownInstances, Scope maxScopeOfKnownInstances);
/**
* Generates a known instance list item.
* @param classInstance the class instance.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateKnownInstance(ClassInstance classInstance, int index);
/**
* Generates the end of the list of known instances for the detailed documentation for a type constructor or type class.
* @param nKnownInstances the number of known instances to be documented.
*/
abstract void endKnownInstancesList(int nKnownInstances);
/**
* Generates the footer portion of the detailed documentation for a type class.
* @param typeClass the type class to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateTypeClassDocFooter(TypeClass typeClass, int index);
/**
* Generates the end of the type class section of the detailed documentation.
* @param nTypeClasses the number of type classes to be documented.
*/
abstract void endTypeClassesDocSection(int nTypeClasses);
/**
* Generates the start of the class instances section of the detailed documentation.
* @param nClassInstances the number of class instances to be documented.
* @param classInstances the array of class instances to be documented.
* @param maxScopeOfClassInstances the maximum scope of the class instances.
*/
abstract void beginClassInstancesDocSection(int nClassInstances, ClassInstance[] classInstances, Scope maxScopeOfClassInstances);
/**
* Generates the detailed documentation for a class instance.
* @param classInstance the class instance to be documented.
* @param index the position of this entry in its enclosing list.
*/
void generateClassInstanceDoc(ClassInstance classInstance, int index) {
////
/// Generate documentation about the class instance itself.
//
generateClassInstanceDocHeader(classInstance, index);
////
/// Generate documentation for each method of this class instance.
//
int nInstanceMethods = classInstance.getNInstanceMethods();
beginInstanceMethodDocList(nInstanceMethods);
TypeClass typeClass = classInstance.getTypeClass();
for (int i = 0; i < nInstanceMethods; i++) {
// no index entries for instance method definitions
ClassMethod classMethod = typeClass.getNthClassMethod(i);
generateInstanceMethodDoc(classInstance, classMethod.getName().getUnqualifiedName(), classMethod, i);
}
endInstanceMethodDocList(nInstanceMethods);
generateClassInstanceDocFooter(classInstance, index);
}
/**
* Generates the header portion of the detailed documentation for a class instance.
* @param classInstance the class instance to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateClassInstanceDocHeader(ClassInstance classInstance, int index);
/**
* Generates the start of the list of instance methods for the detailed documentation for a class instance.
* @param nInstanceMethods the number of instance methods to be documented.
*/
abstract void beginInstanceMethodDocList(int nInstanceMethods);
/**
* Generates the detailed documentation for an instance method.
* @param classInstance the class instance of the instance method.
* @param methodName the name of the instance method.
* @param classMethod the corresponding class method.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateInstanceMethodDoc(ClassInstance classInstance, String methodName, ClassMethod classMethod, int index);
/**
* Generates the end of the list of instance methods for the detailed documentation for a class instance.
* @param nInstanceMethods the number of instance methods to be documented.
*/
abstract void endInstanceMethodDocList(int nInstanceMethods);
/**
* Generates the footer portion of the detailed documentation for a class instance.
* @param classInstance the class instance to be documented.
* @param index the position of this entry in its enclosing list.
*/
abstract void generateClassInstanceDocFooter(ClassInstance classInstance, int index);
/**
* Generates the start of the class instances section of the detailed documentation.
* @param nClassInstances the number of class instances to be documented.
*/
abstract void endClassInstancesDocSection(int nClassInstances);
/**
* Returns whether documentation is generated for the specified module.
* @param moduleName the name of the module to check.
* @return true if documentation is generated for the module; false otherwise.
*/
boolean isDocForModuleGenerated(ModuleName moduleName) {
// The module must exist and it must not be filtered out by the user-specified filter
// for the documentation to be generated.
return programModelManager.hasModuleInProgram(moduleName) && filter.shouldGenerateModule(moduleName);
}
/**
* Returns whether documentation is generated for the specified type constructor.
* @param moduleName the name of the type constructor's module.
* @param unqualifiedName the unqualified name of the type constructor.
* @return true if documentation is generated for the type constructor; false otherwise.
*/
boolean isDocForTypeConsGenerated(ModuleName moduleName, String unqualifiedName) {
////
/// First the entity must exist for its documentation to be generated.
//
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
if (moduleTypeInfo == null) {
return false;
} else {
ScopedEntity entity = moduleTypeInfo.getTypeConstructor(unqualifiedName);
if (entity == null) {
return false;
} else {
////
/// Having found the entity, now defer to the user-specified filter for the final answer.
//
return filter.shouldGenerateScopedEntity(entity);
}
}
}
/**
* Returns whether the specified type constructor should be accepted (based on scope only).
* @param moduleName the name of the type constructor's module.
* @param unqualifiedName the unqualified name of the type constructor.
* @return true if the type constructor is accepted; false otherwise.
*/
boolean shouldAcceptTypeConsBasedOnScopeOnly(ModuleName moduleName, String unqualifiedName) {
////
/// First the entity must exist for its documentation to be generated.
//
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
if (moduleTypeInfo == null) {
return false;
} else {
ScopedEntity entity = moduleTypeInfo.getTypeConstructor(unqualifiedName);
if (entity == null) {
return false;
} else {
////
/// Having found the entity, now defer to the user-specified filter for the final answer.
//
return filter.shouldAcceptScopedEntityBasedOnScopeOnly(entity);
}
}
}
/**
* Returns whether documentation is generated for the specified data constructor.
* @param moduleName the name of the data constructor's module.
* @param unqualifiedName the unqualified name of the data constructor.
* @return true if documentation is generated for the data constructor; false otherwise.
*/
boolean isDocForDataConsGenerated(ModuleName moduleName, String unqualifiedName) {
////
/// First the entity must exist for its documentation to be generated.
//
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
if (moduleTypeInfo == null) {
return false;
} else {
ScopedEntity entity = moduleTypeInfo.getDataConstructor(unqualifiedName);
if (entity == null) {
return false;
} else {
////
/// Having found the entity, now defer to the user-specified filter for the final answer.
//
return filter.shouldGenerateScopedEntity(entity);
}
}
}
/**
* Returns whether documentation is generated for the specified function or class method.
* @param moduleName the name of the function or class method's module.
* @param unqualifiedName the unqualified name of the function or class method.
* @return true if documentation is generated for the function or class method; false otherwise.
*/
boolean isDocForFunctionOrClassMethodGenerated(ModuleName moduleName, String unqualifiedName) {
////
/// First the entity must exist for its documentation to be generated.
//
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
if (moduleTypeInfo == null) {
return false;
} else {
ScopedEntity entity = moduleTypeInfo.getFunctionOrClassMethod(unqualifiedName);
if (entity == null) {
return false;
} else {
////
/// Having found the entity, now defer to the user-specified filter for the final answer.
//
return filter.shouldGenerateScopedEntity(entity);
}
}
}
/**
* Returns whether documentation is generated for the specified type class.
* @param moduleName the name of the type class's module.
* @param unqualifiedName the unqualified name of the type class.
* @return true if documentation is generated for the type class; false otherwise.
*/
boolean isDocForTypeClassGenerated(ModuleName moduleName, String unqualifiedName) {
////
/// First the entity must exist for its documentation to be generated.
//
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
if (moduleTypeInfo == null) {
return false;
} else {
ScopedEntity entity = moduleTypeInfo.getTypeClass(unqualifiedName);
if (entity == null) {
return false;
} else {
////
/// Having found the entity, now defer to the user-specified filter for the final answer.
//
return filter.shouldGenerateScopedEntity(entity);
}
}
}
/**
* Returns whether documentation is generated for the class instance.
* @param classInstance the class instance to check.
* @return true if documentation is generated for the class instance; false otherwise.
*/
boolean isDocForClassInstanceGenerated(ClassInstance classInstance) {
////
/// First check the type class of the instance.
//
if (!filter.shouldAcceptScopedEntityBasedOnScopeOnly(classInstance.getTypeClass())) {
return false;
}
////
/// The type class is accepted, so check the instance type.
//
SourceModel.TypeSignature instanceType = classInstance.getType().toSourceModel();
TypeSigCheckerForTypeConsNotAcceptedBasedOnScopeOnly checker = new TypeSigCheckerForTypeConsNotAcceptedBasedOnScopeOnly();
instanceType.accept(checker, null);
return !checker.hasTypeConsNotAcceptedBasedOnScopeOnly();
}
/**
* Returns whether documentation is generated for both the class instance's type class and instance type.
* @param classInstance the class instance to check.
* @return true if documentation is generated for both the class instance's type class and instance type; false otherwise.
*/
boolean areDocForInstanceClassAndInstanceTypeGenerated(ClassInstance classInstance) {
////
/// First check the type class of the instance.
//
QualifiedName typeClassName = classInstance.getTypeClass().getName();
if (!isDocForTypeClassGenerated(typeClassName.getModuleName(), typeClassName.getUnqualifiedName())) {
return false;
}
////
/// Documentation is generated for the type class, so check the instance type.
//
SourceModel.TypeSignature instanceType = classInstance.getType().toSourceModel();
TypeSigCheckerForTypeConsWhereDocNotGenerated checker = new TypeSigCheckerForTypeConsWhereDocNotGenerated();
instanceType.accept(checker, null);
return !checker.hasTypeConsWhereDocNotGenerated();
}
/**
* Returns the scope of the specified type constructor.
* @param moduleName the name of the type constructor's module.
* @param unqualifiedName the unqualified name of the type constructor.
* @return the scope of the type constructor.
*/
Scope getTypeConstructorScope(ModuleName moduleName, String unqualifiedName) {
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
if (moduleTypeInfo == null) {
return Scope.PRIVATE;
} else {
ScopedEntity entity = moduleTypeInfo.getTypeConstructor(unqualifiedName);
if (entity == null) {
return Scope.PRIVATE;
} else {
return entity.getScope();
}
}
}
/**
* Returns the minimum scope of the class instance's type class and instance type.
* @param classInstance the class instance to check.
* @return the minimum scope of the class instance's type class and instance type.
*/
Scope minScopeForInstanceClassAndInstanceType(ClassInstance classInstance) {
Scope cachedScope = classInstanceMinScopeCache.get(classInstance);
if (cachedScope != null) {
return cachedScope;
}
Scope instanceClassScope = classInstance.getTypeClass().getScope();
SourceModel.TypeSignature instanceType = classInstance.getType().toSourceModel();
MinScopeCalculatorForTypeConsInTypeSig calculator = new MinScopeCalculatorForTypeConsInTypeSig();
instanceType.accept(calculator, null);
Scope instanceTypeMinScope = calculator.getMinScope();
Scope instanceMinScope = minScope(instanceClassScope, instanceTypeMinScope);
classInstanceMinScopeCache.put(classInstance, instanceMinScope);
return instanceMinScope;
}
/**
* Returns the minimum of two scopes (i.e. the less visible of the two scopes).
* @param a the first scope.
* @param b the second scope.
* @return the minimum of the two scopes.
*/
static Scope minScope(Scope a, Scope b) {
if (a.compareTo(b) <= 0) {
return a;
} else {
return b;
}
}
/**
* Returns the maximum of two scopes (i.e. the more visible of the two scopes).
* @param a the first scope.
* @param b the second scope.
* @return the maximum of the two scopes.
*/
static Scope maxScope(Scope a, Scope b) {
if (a.compareTo(b) > 0) {
return a;
} else {
return b;
}
}
/**
* Calculates the maximum scope of all the specified entities.
* @param entities the scoped entities.
* @return the maximum scope of all the specified entities.
*/
static Scope calcMaxScopeOfScopedEntities(ScopedEntity[] entities) {
Scope max = Scope.PRIVATE;
for (final ScopedEntity scopedEntity : entities) {
max = maxScope(max, scopedEntity.getScope());
// we're done if the maximum is the public scope, since there's no scope more visible than public
if (max == Scope.PUBLIC) {
break;
}
}
return max;
}
/**
* Calculates the maximum scope of all the specified entities.
* @param entities the scoped entities.
* @return the maximum scope of all the specified entities.
*/
static Scope calcMaxScopeOfScopedEntities(Collection<? extends ScopedEntity> entities) {
Scope max = Scope.PRIVATE;
for (final ScopedEntity scopedEntity : entities) {
max = maxScope(max, scopedEntity.getScope());
// we're done if the maximum is the public scope, since there's no scope more visible than public
if (max == Scope.PUBLIC) {
break;
}
}
return max;
}
/**
* Calculates the maximum scope of all the specified instances.
* @param classInstances the class instances.
* @return the maximum scope of all the specified instances.
*/
Scope calcMaxScopeOfClassInstances(ClassInstance[] classInstances) {
Scope max = Scope.PRIVATE;
for (final ClassInstance classInstance : classInstances) {
max = maxScope(max, minScopeForInstanceClassAndInstanceType(classInstance));
// we're done if the maximum is the public scope, since there's no scope more visible than public
if (max == Scope.PUBLIC) {
break;
}
}
return max;
}
/**
* Calculates the maximum scope of all the specified instances.
* @param classInstances the class instances.
* @return the maximum scope of all the specified instances.
*/
Scope calcMaxScopeOfClassInstances(Collection<ClassInstance> classInstances) {
Scope max = Scope.PRIVATE;
for (final ClassInstance classInstance : classInstances) {
max = maxScope(max, minScopeForInstanceClassAndInstanceType(classInstance));
// we're done if the maximum is the public scope, since there's no scope more visible than public
if (max == Scope.PUBLIC) {
break;
}
}
return max;
}
/**
* @return the moduleNameResolverForDocumentedModules
*/
ModuleNameResolver getModuleNameResolverForDocumentedModules() {
return moduleNameResolverForDocumentedModules;
}
}