Package com.redhat.ceylon.ceylondoc

Source Code of com.redhat.ceylon.ceylondoc.ClassOrPackageDoc$ParameterDocData

/*
* Copyright Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the authors tag. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*
* This particular file is subject to the "Classpath" exception as provided in the
* LICENSE file that accompanied this code.
*
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License,
* along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*/

package com.redhat.ceylon.ceylondoc;

import static com.redhat.ceylon.ceylondoc.Util.findBottomMostRefinedDeclaration;
import static com.redhat.ceylon.ceylondoc.Util.getDoc;
import static com.redhat.ceylon.ceylondoc.Util.getModifiers;
import static com.redhat.ceylon.ceylondoc.Util.getNameWithContainer;
import static com.redhat.ceylon.ceylondoc.Util.isAbbreviatedType;
import static com.redhat.ceylon.ceylondoc.Util.isEmpty;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.antlr.runtime.CommonToken;

import com.redhat.ceylon.compiler.java.codegen.Decl;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.model.Annotation;
import com.redhat.ceylon.compiler.typechecker.model.Class;
import com.redhat.ceylon.compiler.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Functional;
import com.redhat.ceylon.compiler.typechecker.model.Method;
import com.redhat.ceylon.compiler.typechecker.model.MethodOrValue;
import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.model.Parameter;
import com.redhat.ceylon.compiler.typechecker.model.ParameterList;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.Scope;
import com.redhat.ceylon.compiler.typechecker.model.Setter;
import com.redhat.ceylon.compiler.typechecker.model.TypeAlias;
import com.redhat.ceylon.compiler.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.TypeParameter;
import com.redhat.ceylon.compiler.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.model.Value;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;

public abstract class ClassOrPackageDoc extends CeylonDoc {
   
    private static final Set<String> simpleDefaultValues = new HashSet<String>();
    static {
        simpleDefaultValues.add("null");
        simpleDefaultValues.add("true");
        simpleDefaultValues.add("false");
        simpleDefaultValues.add("0");
        simpleDefaultValues.add("1");
        simpleDefaultValues.add("-1");
        simpleDefaultValues.add("0.0");
        simpleDefaultValues.add("1.0");
        simpleDefaultValues.add("-1.0");
        simpleDefaultValues.add("[]");
        simpleDefaultValues.add("\"\"");
    }
   
    public ClassOrPackageDoc(Module module, CeylonDocTool tool, Writer writer) {
    super(module, tool, writer);
  }
   
    protected final void doc(TypeAlias alias) throws IOException {
        open("tr");
       
        open("td id='" + alias.getName() + "' nowrap");
        writeIcon(alias);
        around("code class='decl-label'", alias.getName());
        close("td");
       
        open("td");
        writeLinkOneSelf(alias);
        writeLinkSource(alias);
        writeTagged(alias);
        open("code class='signature'");
        around("span class='modifiers'", getModifiers(alias));
        write(" ");
        open("span class='type-identifier'");
        write(alias.getName());
        close("span");
        if (!alias.getTypeParameters().isEmpty()) {
            writeTypeParameters(alias.getTypeParameters());
            writeTypeParametersConstraints(alias.getTypeParameters());
            open("div class='type-alias-specifier'");
        }
        around("span class='specifier'", "=> ");
        linkRenderer().to(alias.getExtendedType()).write();
        if (!alias.getTypeParameters().isEmpty()) {
            close("div"); // type-alias-specifier
        }
        close("code"); // signature
        writeDescription(alias);
        close("td");
       
        close("tr");
    }

    protected final void doc(ClassOrInterface d) throws IOException {
        open("tr");
       
        open("td id='" + d.getName() + "' nowrap");
        writeIcon(d);
        open("a class='decl-label' href='"+ linkRenderer().to(d).getUrl() +"'");
        around("code", d.getName());
        close("a");
        close("td");
       
        open("td");
        writeLinkOneSelf(d);
        writeLinkSourceCode(d);
        writeTagged(d);
        open("code class='signature'");
        around("span class='modifiers'", getModifiers(d));
        write(" ");
        linkRenderer().to(d.getType()).printAbbreviated(!isAbbreviatedType(d)).printTypeParameterDetail(true).write();
        writeTypeParametersConstraints(d.getTypeParameters());
        close("code");
        writeDescription(d);
        close("td");
       
        close("tr");
    }

    protected final void doc(TypedDeclaration d) throws IOException {
        // put the id on the td because IE8 doesn't support id attributes on tr (yeah right)
        open("tr");
       
        open("td id='" + d.getName() + "' nowrap");
        writeIcon(d);
        around("code class='decl-label'", d.getName());
        close("td");
       
        open("td");
        writeLinkOneSelf(d);
        writeLinkSource(d);
        writeTagged(d);
       
        if(d instanceof Functional)
            writeParameterLinksIfRequired((Functional) d);
        open("code class='signature'");
        around("span class='modifiers'", getModifiers(d));
        write(" ");
       
        if( d instanceof Functional && ((Functional) d).isDeclaredVoid() ) {
            around("span class='void'", "void");
        } else {
            linkRenderer().to(d.getType()).write();   
        }
       
        write(" ");
        open("span class='identifier'");
        write(d.getName());
        close("span");
        if( isConstantValue(d) ) {
            writeConstantValue((Value) d);
        }
        if( d instanceof Functional ) {
            Functional f = (Functional) d;
            writeTypeParameters(f.getTypeParameters());
            writeParameterList(f);
            writeTypeParametersConstraints(f.getTypeParameters());
        }
        if (d instanceof Value) {
            Setter setter = ((Value) d).getSetter();
            if (setter != null && Util.getAnnotation(setter.getAnnotations(), "doc") != null) {
                tool.warningSetterDoc(d.getQualifiedNameString(), d);
            }
        }
        close("code");
        writeDescription(d);
        close("td");
        close("tr");
    }
   
    private boolean isConstantValue(Declaration d) {
        if(Decl.isValue(d)) {
            Value value = (Value) d;
            if( value.isShared() && !value.isVariable() ) {
                Unit unit = value.getUnit();
                TypeDeclaration type = value.getTypeDeclaration();
               
                if (type == unit.getSequentialDeclaration()) {
                    ProducedType elementType = unit.getIteratedType(value.getType());
                    type = elementType.getDeclaration();
                }

                if (unit.getStringDeclaration().equals(type)
                        || unit.getIntegerDeclaration().equals(type)
                        || unit.getFloatDeclaration().equals(type)
                        || unit.getCharacterDeclaration().equals(type)) {
                    return true;
                }
            }
        }
        return false;
    }

    private void writeConstantValue(Value v) throws IOException {
        Node node = tool.getNode(v);
        PhasedUnit pu = tool.getUnit(v);
        if (pu == null || !(node instanceof Tree.AttributeDeclaration)) {
            return;
        }
       
        Tree.AttributeDeclaration attribute = (Tree.AttributeDeclaration) node;
        Tree.SpecifierOrInitializerExpression specifierExpression = attribute.getSpecifierOrInitializerExpression();
        if (specifierExpression == null) {
            return;
        }
       
        String value = getSourceCode(pu, specifierExpression);
        int newLineIndex = value.indexOf("\n");
        String valueFirstLine = newLineIndex != -1 ? value.substring(0, newLineIndex) : value;

        around("span class='specifier'", valueFirstLine);
        if (newLineIndex != -1) {
            around("a class='specifier-ellipsis' href='#' title='Click for expand the rest of value.'", "...");
            open("div class='specifier-rest'");
            write(value.substring(newLineIndex + 1));
            close("div");
        }
    }

    private void writeDescription(Declaration d) throws IOException {
        open("div class='description'");
        writeDeprecated(d);
        String doc = getDoc(d, linkRenderer());
        if (isEmpty(doc)) {
            tool.warningMissingDoc(d.getQualifiedNameString(), d);
        }
        around("div class='doc section'", doc);
        if( d instanceof MethodOrValue ) {
            writeAnnotations(d);
          writeParameters(d);
            writeThrows(d);       
            writeBy(d);
            writeSee(d);
            writeLinkToRefinedDeclaration((MethodOrValue)d);
        }
        if (d instanceof TypeAlias) {
            writeAnnotations(d);
            writeBy(d);
            writeSee(d);
        }
        close("div"); // description
    }
   
    private void writeLinkOneSelf(Declaration d) throws IOException {
        String url = linkRenderer().to(getFromObject()).useAnchor(d).getUrl();
        if (url != null) {
            open("a class='link-one-self' title='Link to this declaration' href='" + url + "'");
            write("<i class='icon-link'></i>");
            close("a");
        }
    }

    private void writeLinkSource(Declaration d) throws IOException {
        if (!tool.isIncludeSourceCode()) {
            return;
        }
        String srcUrl;
        if (d.isToplevel()) {
            srcUrl = linkRenderer().getSrcUrl(d);
        } else {
            srcUrl = linkRenderer().getSrcUrl(d.getContainer());
        }
        int[] lines = tool.getDeclarationSrcLocation(d);
        if(lines != null){
            open("a class='link-source-code' title='Link to source code' href='" + srcUrl + "#" + lines[0] + "," + lines[1] + "'");
            write("<i class='icon-source-code'></i>");
            write("Source Code");
            close("a");
        }
    }

    private void writeLinkToRefinedDeclaration(MethodOrValue d) throws IOException {
        Declaration topMostRefinedDecl = d.getRefinedDeclaration();
        if (topMostRefinedDecl != null && topMostRefinedDecl != d) {
            Declaration bottomMostRefinedDecl = findBottomMostRefinedDeclaration(d);
            open("div class='refined section'");
            around("span class='title'", "Refines ");
            if (bottomMostRefinedDecl != null && bottomMostRefinedDecl != topMostRefinedDecl) {
                linkRenderer().to(bottomMostRefinedDecl).withinText(true)
                    .useCustomText(getNameWithContainer(bottomMostRefinedDecl)).write();
                around("span class='title'", " ultimately refines ");
                linkRenderer().to(topMostRefinedDecl).withinText(true)
                    .useCustomText(getNameWithContainer(topMostRefinedDecl)).write();
            } else {
                linkRenderer().to(topMostRefinedDecl).withinText(true)
                    .useCustomText(getNameWithContainer(topMostRefinedDecl)).write();
            }
            close("div");
        }
    }

    protected final void writeTypeParameters(List<TypeParameter> typeParameters) throws IOException {
        if (typeParameters != null && !typeParameters.isEmpty()) {
            write("&lt;");
            write("<span class='type-parameter'>");
            boolean first = true;
            for (TypeParameter typeParam : typeParameters) {
                if (first) {
                    first = false;
                } else {
                    write(", ");
                }
                if (typeParam.isContravariant()) {
                    write("<span class='type-parameter-keyword'>in </span>");
                }
                if (typeParam.isCovariant()) {
                    write("<span class='type-parameter-keyword'>out </span>");
                }
                write(typeParam.getName());
                if (typeParam.isDefaulted() && typeParam.getDefaultTypeArgument() != null){
                    write("<span class='type-parameter'> = </span>");
                    write("<span class='type-parameter-value'>");
                    write(linkRenderer().to(typeParam.getDefaultTypeArgument()).getLink());
                    write("</span>");
                }
            }
            write("</span>");
            write("&gt;");
        }
    }
   
    protected final void writeTypeParametersConstraints(List<TypeParameter> typeParameters) throws IOException {
        for (TypeParameter typeParam : typeParameters) {
            if (typeParam.isConstrained()) {
                open("div class='type-parameter-constraint'");

                write("<span class='type-parameter-keyword'>given</span>");
                write(" ");
                around("span class='type-parameter'", typeParam.getName());
               
                writeSatisfiedTypes(typeParam);
                writeCaseTypes(typeParam);

                if (typeParam.getParameterList() != null) {
                    writeParameterList(typeParam);
                }

                close("div");
            }
        }
    }

    protected final void writeInheritance(TypeDeclaration typeDeclaration) throws IOException {
        if (typeDeclaration.getCaseTypes()!=null &&
                !typeDeclaration.getCaseTypes().isEmpty()) {
            open("div class='inheritance-satisfies'");
            writeCaseTypes(typeDeclaration);
            close("div");
        }
        if (typeDeclaration instanceof Class &&
                typeDeclaration.getExtendedType()!=null) {
            open("div class='inheritance-extends'");
            write("<span class='keyword'>extends</span>");
            write(" ");
            linkRenderer().to(typeDeclaration.getExtendedType()).write();
            close("div");
        }
        if (typeDeclaration.getSatisfiedTypes()!=null &&
                !typeDeclaration.getSatisfiedTypes().isEmpty()) {
            open("div class='inheritance-of'");
            writeSatisfiedTypes(typeDeclaration);
            close("div");
        }
    }

    private void writeCaseTypes(TypeDeclaration typeDeclaration) throws IOException {
        List<ProducedType> caseTypes = typeDeclaration.getCaseTypes();
        if (caseTypes != null && !caseTypes.isEmpty()) {
            write(" ");
            write("<span class='type-parameter-keyword'>of</span>");
            write(" ");
            boolean first = true;
            for (ProducedType caseType : caseTypes) {
                if (first) {
                    first = false;
                } else {
                    write(" | ");
                }
                linkRenderer().to(caseType).write();
            }
        }
    }

    private void writeSatisfiedTypes(TypeDeclaration typeDeclaration)
            throws IOException {
        List<ProducedType> satisfiedTypes = typeDeclaration.getSatisfiedTypes();
        if (satisfiedTypes != null && !satisfiedTypes.isEmpty()) {
            write(" ");
            write("<span class='keyword'>satisfies</span>");
            write(" ");
            boolean first = true;
            for (ProducedType satisfiedType : satisfiedTypes) {
                if (first) {
                    first = false;
                } else {
                    write(" &amp; ");
                }
                linkRenderer().to(satisfiedType).write();
            }
        }
    }
   
    protected final void writeParameterLinksIfRequired(Functional f) throws IOException {
        writeParameterLinksIfRequired(f, true, "");
    }

    private final void writeParameterLinksIfRequired(Functional f, boolean onlyIfNoDoc, String idPrefix) throws IOException {
        Map<Parameter, Map<Tree.Assertion, List<Tree.Condition>>> parametersAssertions = null;
        if (onlyIfNoDoc) {
            parametersAssertions = getParametersAssertions((Declaration) f);
        }
       
        for (ParameterList parameterList : f.getParameterLists()) {
            for (Parameter parameter : parameterList.getParameters()) {
                boolean isRequired = true;

                if (onlyIfNoDoc) {
                    ParameterDocData parameterDocData = getParameterDocData(parameter, parametersAssertions);
                    if (!parameterDocData.isEmpty()) {
                        isRequired = false;
                    }
                }

                if (isRequired) {
                    around("a id='" + idPrefix + f.getName() + "-" + parameter.getName() + "'", "");
                   
                    // if parameter is function, we need to produce links to its parameters
                    if (parameter.getModel() instanceof Method) {
                        writeParameterLinksIfRequired((Method) parameter.getModel(), false, idPrefix + f.getName() + "-");
                    }
                }
            }
        }
    }

    protected final void writeParameterList(Functional f) throws IOException {
        for (ParameterList lists : f.getParameterLists()) {
            write("(");
            boolean first = true;
            for (Parameter param : lists.getParameters()) {
                if (!first) {
                    write(", ");
                } else {
                    first = false;
                }
               
                if (param.getModel() instanceof Method) {
                    writeFunctionalParameter(param);
                } else {
                    linkRenderer().to(param.getType()).write();
                    write(" ");
                    around("span class='parameter'", param.getName());
                }
               
                if (param.isDefaulted()) {
                    String defaultValue = getParameterDefaultValue(param);
                    if (defaultValue != null) {
                        around("span class='parameter-default-value'", " = ");
                        if (simpleDefaultValues.contains(defaultValue)) {
                            around("span class='parameter-default-value' title='Parameter default value'", defaultValue);
                        } else {
                            around("a class='parameter-default-value' href='#" + f.getName() + "-" + param.getName() + "' title='Go to parameter default value'", "...");
                        }
                    }
                }
               
            }
            write(")");
        }
    }
   
    private String getParameterDefaultValue(Parameter param) throws IOException {
        String defaultValue = null;
       
        if( param.isDefaulted() ) {
            PhasedUnit pu = tool.getParameterUnit(param);
            Node paramNode = tool.getParameterNode(param);
            if (pu != null && paramNode instanceof Tree.Parameter) {
                Tree.SpecifierOrInitializerExpression defArg = getDefaultArgument((Tree.Parameter) paramNode);
                if (defArg != null) {
                    defaultValue = getSourceCode(pu, defArg.getExpression());
                    if (defaultValue != null) {
                        defaultValue = defaultValue.trim();
                    }
                }
            }
        }
       
        return defaultValue;
    }
   
    private Tree.SpecifierOrInitializerExpression getDefaultArgument(Tree.Parameter parameter) {
        if (parameter instanceof Tree.InitializerParameter) {
            return ((Tree.InitializerParameter)parameter).getSpecifierExpression();
        } else if (parameter instanceof Tree.ValueParameterDeclaration) {
            return ((Tree.AttributeDeclaration)((Tree.ValueParameterDeclaration)parameter).getTypedDeclaration()).getSpecifierOrInitializerExpression();
        } else if (parameter instanceof Tree.FunctionalParameterDeclaration) {
            return ((Tree.MethodDeclaration)((Tree.FunctionalParameterDeclaration)parameter).getTypedDeclaration()).getSpecifierExpression();
        }
        return null;
    }

    private void writeFunctionalParameter(Parameter functionParam) throws IOException {
        if( functionParam.isDeclaredVoid() ) {
            around("span class='void'", "void");
        } else {
            linkRenderer().to(functionParam.getType()).write();
        }
        write(" ");
        write(functionParam.getName());
        writeParameterList((Method)functionParam.getModel());
    }

    protected final void writeParameters(Declaration decl) throws IOException {
        if( decl instanceof Functional ) {
            Map<Parameter, Map<Tree.Assertion, List<Tree.Condition>>> parametersAssertions = getParametersAssertions(decl);
            boolean first = true;
            List<ParameterList> parameterLists = ((Functional)decl).getParameterLists();
            for (ParameterList parameterList : parameterLists) {
                for (Parameter parameter : parameterList.getParameters()) {
                    ParameterDocData parameterDocData = getParameterDocData(parameter, parametersAssertions);
                    if( !parameterDocData.isEmpty()) {
                        if( first ) {
                            first = false;
                            open("div class='parameters section'");
                            around("span class='title'", "Parameters: ");
                            open("ul");
                        }
                        open("li");
                        open("code");
                       
                        around("span class='parameter' id='" + decl.getName() + "-" + parameter.getName() + "'", parameter.getName());
                       
                        // if parameter is function, we need to produce links to its parameters
                        if (parameter.getModel() instanceof Method) {
                            writeParameterLinksIfRequired((Method) parameter.getModel(), false, decl.getName() + "-");
                        }
                       
                        if (!isEmpty(parameterDocData.defaultValue)) {
                            around("span class='parameter-default-value' title='Parameter default value'", " = " + parameterDocData.defaultValue);
                        }
                       
                        close("code");
                       
                        if (!isEmpty(parameterDocData.doc)) {
                            around("div class='doc section'", parameterDocData.doc);
                        }
                        writeParameterAssertions(decl, parameterDocData.parameterAssertions);
                       
                        close("li");
                    }
                }
            }         
            if (!first) {
                close("ul");
                close("div");
            }
        }
    }

    private void writeParameterAssertions(Declaration decl, Map<Tree.Assertion, List<Tree.Condition>> parameterAssertions) throws IOException {
        if (parameterAssertions == null || parameterAssertions.isEmpty()) {
            return;
        }
       
        PhasedUnit pu = tool.getUnit(decl);
       
        open("div class='assertions' title='Parameter assertions'");
        open("ul");

        for (Tree.Assertion assertion : parameterAssertions.keySet()) {

            List<Annotation> annotations = new ArrayList<Annotation>();
            com.redhat.ceylon.compiler.typechecker.analyzer.Util.buildAnnotations(assertion.getAnnotationList(), annotations);

            String doc = Util.getRawDoc(annotations);
            if (!Util.isEmpty(doc)) {
                open("li");
                write("<i class='icon-assertion'></i>");
                write(Util.wikiToHTML(doc, linkRenderer()));
                close("li");
            } else {
                for (Tree.Condition c : parameterAssertions.get(assertion)) {
                    String sourceCode = getSourceCode(pu, c);
                    open("li");
                    write("<i class='icon-assertion'></i>");
                    around("code", sourceCode);
                    close("li");
                }
            }
        }

        close("ul");
        close("div");
    }

  protected final void writeThrows(Declaration decl) throws IOException {
        boolean first = true;
        for (Annotation annotation : decl.getAnnotations()) {
            if (annotation.getName().equals("throws")) {

                String excType = annotation.getPositionalArguments().get(0);
                String excDesc = annotation.getPositionalArguments().size() == 2 ? annotation.getPositionalArguments().get(1) : null;
               
                if (first) {
                    first = false;
                    open("div class='throws section'");
                    around("span class='title'", "Throws ");
                    open("ul");
                }

                open("li");
               
                linkRenderer().to(excType).withinText(true).useScope(decl).write();
               
                if (excDesc != null) {
                    write(Util.wikiToHTML(excDesc, linkRenderer().useScope(decl)));
                }

                close("li");
            }
        }
        if (!first) {
            close("ul");
            close("div");
        }
        tool.warningMissingThrows(decl);
    }
   
    private void writeDeprecated(Declaration decl) throws IOException {
        Annotation deprecated = Util.findAnnotation(decl, "deprecated");
        if (deprecated != null) {
            open("div class='deprecated section'");
            String text = "<span class='title'>Deprecated: </span>";
            if (!deprecated.getPositionalArguments().isEmpty()) {
                String reason = deprecated.getPositionalArguments().get(0);
                if (reason != null) {
                    text += reason;
                }
            }
            write(Util.wikiToHTML(text, linkRenderer().useScope(decl)));
            close("div");
        }
    }
   
    protected final void writeSee(Declaration decl) throws IOException {
        Annotation see = Util.getAnnotation(decl.getAnnotations(), "see");
        if(see == null)
            return;

        open("div class='see section'");
        around("span class='title'", "See also ");
       
        open("span class='value'");
        boolean first = true;
        for (String target : see.getPositionalArguments()) {
            if (!first) {
                write(", ");
            } else {
                first = false;
            }
            //TODO: add 'identifier' or 'type-identitier' CSS class
            linkRenderer().to(target).withinText(true).useScope(decl)
                .printAbbreviated(false).printTypeParameters(false).write();
        }
        close("span");
       
        close("div");
    }

    protected final void writeTagged(Declaration decl) throws IOException {
        List<String> tags = Util.getTags(decl);
        if (!tags.isEmpty()) {
            open("div class='tags section'");
            Iterator<String> tagIterator = tags.iterator();
            while (tagIterator.hasNext()) {
                String tag = tagIterator.next();
                write("<a class='tag label' name='" + tag + "' href='search.html?q=" + tag + "'>" + tag + "</a>");
            }
            close("div");
        }
    }

    private String getSourceCode(PhasedUnit pu, Node node) throws IOException {
        int startIndex = ((CommonToken) node.getToken()).getStartIndex();
        int stopIndex = ((CommonToken) node.getEndToken()).getStopIndex();
   
        StringBuilder sourceCodeBuilder = new StringBuilder();
        BufferedReader sourceCodeReader = new BufferedReader(new InputStreamReader(pu.getUnitFile().getInputStream()));
        try {
            while (true) {
                int c = sourceCodeReader.read();
                if (c == -1 || sourceCodeBuilder.length() > stopIndex) {
                    break;
                }
                sourceCodeBuilder.append((char) c);
            }
        } finally {
            sourceCodeReader.close();
        }

        String sourceCode = sourceCodeBuilder.substring(startIndex, stopIndex + 1);
        sourceCode = sourceCode.replaceAll("&", "&amp;");
        sourceCode = sourceCode.replaceAll("<", "&lt;");
        sourceCode = sourceCode.replaceAll(">", "&gt;");
        return sourceCode;
    }
   
    private Map<Parameter, Map<Tree.Assertion, List<Tree.Condition>>> getParametersAssertions(final Declaration decl) {
        final Map<Parameter, Map<Tree.Assertion, List<Tree.Condition>>> parametersAssertions = new LinkedHashMap<Parameter, Map<Tree.Assertion, List<Tree.Condition>>>();
       
        if (((Functional) decl).getParameterLists().isEmpty()) {
            return parametersAssertions;
        }

        Node node = tool.getNode(decl);
        PhasedUnit pu = tool.getUnit(decl);
        if (node == null || pu == null) {
            return parametersAssertions;
        }

        Tree.Body body = null;
        if (node instanceof Tree.MethodDefinition) {
            body = ((Tree.MethodDefinition) node).getBlock();
        } else if (node instanceof Tree.ClassDefinition) {
            body = ((Tree.ClassDefinition) node).getClassBody();
        }

        if (body == null) {
            return parametersAssertions;
        }

        final Map<String, Parameter> parametersNames = new HashMap<String, Parameter>();
        for (ParameterList parameterList : ((Functional) decl).getParameterLists()) {
            for (Parameter parameter : parameterList.getParameters()) {
                parametersNames.put(parameter.getName(), parameter);
            }
        }

        body.visitChildren(new Visitor() {

            private boolean stop = false;
            private Tree.Assertion assertion = null;
            private Set<Parameter> referencedParameters = new HashSet<Parameter>();

            @Override
            public void visit(Tree.Assertion that) {
                assertion = that;
                super.visit(that);
                assertion = null;
            }

            @Override
            public void visit(Tree.Condition that) {
                referencedParameters.clear();
                super.visit(that);
                if (assertion != null && !referencedParameters.isEmpty()) {
                    for (Parameter referencedParameter : referencedParameters) {
                        Map<Tree.Assertion, List<Tree.Condition>> parameterAssertions = parametersAssertions.get(referencedParameter);
                        if (parameterAssertions == null) {
                            parameterAssertions = new LinkedHashMap<Tree.Assertion, List<Tree.Condition>>();
                            parametersAssertions.put(referencedParameter, parameterAssertions);
                        }

                        List<Tree.Condition> parameterConditions = parameterAssertions.get(assertion);
                        if (parameterConditions == null) {
                            parameterConditions = new ArrayList<Tree.Condition>();
                            parameterAssertions.put(assertion, parameterConditions);
                        }

                        parameterConditions.add(that);
                    }
                }
            }

            @Override
            public void visit(Tree.BaseMemberExpression that) {
                if (assertion != null) {
                    Declaration d = that.getDeclaration();
                    Scope realScope = com.redhat.ceylon.compiler.typechecker.model.Util.getRealScope(d.getScope());
                    if (parametersNames.containsKey(d.getName()) && realScope == decl) {
                        referencedParameters.add(parametersNames.get(d.getName()));
                    }
                }
                super.visit(that);
            }

            @Override
            public void visit(Tree.Statement that) {
                if (assertion == null) {
                    stop = true;
                }
                super.visit(that);
            }

            @Override
            public void visitAny(Node that) {
                if (!stop) {
                    super.visitAny(that);
                }
            }

        });

        return parametersAssertions;
    }
   
    private ParameterDocData getParameterDocData(Parameter parameter, Map<Parameter, Map<Tree.Assertion, List<Tree.Condition>>> parametersAssertions) throws IOException {
        String doc = getDoc(parameter.getModel(), linkRenderer());
        String defaultValue = getParameterDefaultValue(parameter);
        Map<Tree.Assertion, List<Tree.Condition>> parameterAssertions = parametersAssertions.get(parameter);
        return new ParameterDocData(doc, defaultValue, parameterAssertions);
    }
   
    private static class ParameterDocData {
       
        final String doc;
        final String defaultValue;
        final Map<Tree.Assertion, List<Tree.Condition>> parameterAssertions;
       
        public ParameterDocData(String doc, String defaultValue, Map<Tree.Assertion, List<Tree.Condition>> parameterAssertions) {
            this.doc = doc;
            this.defaultValue = defaultValue;
            this.parameterAssertions = parameterAssertions;
        }
       
        boolean isEmpty() {
            return doc.isEmpty() && defaultValue == null && parameterAssertions == null;
        }
       
    }

}
TOP

Related Classes of com.redhat.ceylon.ceylondoc.ClassOrPackageDoc$ParameterDocData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.