1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /**
  27  *  A utility class.
  28  *
  29  *  <p><b>This is NOT part of any supported API.
  30  *  If you write code that depends on this, you do so at your own risk.
  31  *  This code and its internal interfaces are subject to change or
  32  *  deletion without notice.</b>
  33  */
  34 
  35 package jdk.javadoc.internal.doclets.toolkit;
  36 
  37 import java.net.URI;
  38 import java.util.ArrayList;
  39 import java.util.HashMap;
  40 import java.util.List;
  41 
  42 import javax.lang.model.element.Element;
  43 import javax.lang.model.element.ExecutableElement;
  44 import javax.lang.model.element.Name;
  45 import javax.lang.model.element.PackageElement;
  46 import javax.lang.model.element.VariableElement;
  47 import javax.lang.model.util.Elements;
  48 import javax.tools.FileObject;
  49 import javax.tools.JavaFileObject;
  50 import javax.tools.SimpleJavaFileObject;
  51 
  52 import com.sun.source.doctree.DocCommentTree;
  53 import com.sun.source.doctree.DocTree;
  54 import com.sun.source.doctree.IdentifierTree;
  55 import com.sun.source.doctree.ReferenceTree;
  56 import com.sun.source.doctree.TextTree;
  57 import com.sun.source.util.DocTreeFactory;
  58 import com.sun.source.util.DocTreePath;
  59 import com.sun.source.util.DocTrees;
  60 import com.sun.source.util.TreePath;
  61 import com.sun.tools.javac.util.DefinedBy;
  62 import com.sun.tools.javac.util.DefinedBy.Api;
  63 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
  64 
  65 public class CommentUtils {
  66 
  67     final BaseConfiguration configuration;
  68     final Resources resources;
  69     final DocTreeFactory treeFactory;
  70     final HashMap<Element, DocCommentDuo> dcTreesMap = new HashMap<>();
  71     final DocTrees trees;
  72     final Elements elementUtils;
  73 
  74     protected CommentUtils(BaseConfiguration configuration) {
  75         this.configuration = configuration;
  76         resources = configuration.getResources();
  77         trees = configuration.docEnv.getDocTrees();
  78         treeFactory = trees.getDocTreeFactory();
  79         elementUtils = configuration.docEnv.getElementUtils();
  80     }
  81 
  82     public List<? extends DocTree> makePropertyDescriptionTree(List<? extends DocTree> content) {
  83         List<DocTree> out = new ArrayList<>();
  84         Name name = elementUtils.getName("propertyDescription");
  85         out.add(treeFactory.newUnknownBlockTagTree(name, content));
  86         return out;
  87     }
  88 
  89     public List<? extends DocTree> makePropertyDescriptionTree(String content) {
  90         List<DocTree> inlist = new ArrayList<>();
  91         inlist.add(treeFactory.newCommentTree(content));
  92         List<DocTree> out = new ArrayList<>();
  93         Name name = elementUtils.getName("propertyDescription");
  94         out.add(treeFactory.newUnknownBlockTagTree(name, inlist));
  95         return out;
  96     }
  97 
  98     public List<? extends DocTree> makeFirstSentenceTree(String content) {
  99         List<DocTree> out = new ArrayList<>();
 100         out.add(treeFactory.newTextTree(content));
 101         return out;
 102     }
 103 
 104     public DocTree makeSeeTree(String sig, Element e) {
 105         List<DocTree> list = new ArrayList<>();
 106         list.add(treeFactory.newReferenceTree(sig));
 107         return treeFactory.newSeeTree(list);
 108     }
 109 
 110     public DocTree makeTextTree(String content) {
 111         TextTree text = treeFactory.newTextTree(content);
 112         return (DocTree) text;
 113     }
 114 
 115     public void setEnumValuesTree(Element e) {
 116         Utils utils = configuration.utils;
 117         String klassName = utils.getSimpleName(utils.getEnclosingTypeElement(e));
 118 
 119         List<DocTree> fullBody = new ArrayList<>();
 120         fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.fullbody", klassName)));
 121 
 122         List<DocTree> descriptions = new ArrayList<>();
 123         descriptions.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.return")));
 124 
 125         List<DocTree> tags = new ArrayList<>();
 126         tags.add(treeFactory.newReturnTree(descriptions));
 127         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
 128         dcTreesMap.put(e, new DocCommentDuo(null, docTree));
 129     }
 130 
 131     public void setEnumValueOfTree(Element e) {
 132 
 133         List<DocTree> fullBody = new ArrayList<>();
 134         fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.fullbody")));
 135 
 136         List<DocTree> tags = new ArrayList<>();
 137 
 138         List<DocTree> paramDescs = new ArrayList<>();
 139         paramDescs.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.param_name")));
 140         ExecutableElement ee = (ExecutableElement) e;
 141         java.util.List<? extends VariableElement> parameters = ee.getParameters();
 142         VariableElement param = parameters.get(0);
 143         IdentifierTree id = treeFactory.newIdentifierTree(elementUtils.getName(param.getSimpleName().toString()));
 144         tags.add(treeFactory.newParamTree(false, id, paramDescs));
 145 
 146         List<DocTree> returnDescs = new ArrayList<>();
 147         returnDescs.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.return")));
 148         tags.add(treeFactory.newReturnTree(returnDescs));
 149 
 150         List<DocTree> throwsDescs = new ArrayList<>();
 151         throwsDescs.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.throws_ila")));
 152 
 153         ReferenceTree ref = treeFactory.newReferenceTree("java.lang.IllegalArgumentException");
 154         tags.add(treeFactory.newThrowsTree(ref, throwsDescs));
 155 
 156         throwsDescs = new ArrayList<>();
 157         throwsDescs.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.throws_npe")));
 158 
 159         ref = treeFactory.newReferenceTree("java.lang.NullPointerException");
 160         tags.add(treeFactory.newThrowsTree(ref, throwsDescs));
 161 
 162         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
 163 
 164         dcTreesMap.put(e, new DocCommentDuo(null, docTree));
 165     }
 166 
 167     /*
 168      * Returns the TreePath/DocCommentTree duo for synthesized element.
 169      */
 170     public DocCommentDuo getSyntheticCommentDuo(Element e) {
 171         return dcTreesMap.get(e);
 172     }
 173 
 174     /*
 175      * Returns the TreePath/DocCommentTree duo for html sources.
 176      */
 177     public DocCommentDuo getHtmlCommentDuo(Element e) {
 178         FileObject fo = null;
 179         PackageElement pe = null;
 180         switch (e.getKind()) {
 181             case OTHER:
 182                 if (e instanceof DocletElement) {
 183                     DocletElement de = (DocletElement)e;
 184                     fo = de.getFileObject();
 185                     pe = de.getPackageElement();
 186                 }
 187                 break;
 188             case PACKAGE:
 189                 fo = configuration.workArounds.getJavaFileObject((PackageElement)e);
 190                 pe = (PackageElement)e;
 191                 break;
 192             default:
 193                 return null;
 194         }
 195         if (fo == null) {
 196             return null;
 197         }
 198 
 199         DocCommentTree dcTree = trees.getDocCommentTree(fo);
 200         if (dcTree == null) {
 201             return null;
 202         }
 203         DocTreePath treePath = trees.getDocTreePath(fo, pe);
 204         return new DocCommentDuo(treePath.getTreePath(), dcTree);
 205     }
 206 
 207     public DocCommentTree parse(URI uri, String text) {
 208         return trees.getDocCommentTree(new SimpleJavaFileObject(
 209                 uri, JavaFileObject.Kind.SOURCE) {
 210             @Override @DefinedBy(Api.COMPILER)
 211             public CharSequence getCharContent(boolean ignoreEncoding) {
 212                 return text;
 213             }
 214         });
 215     }
 216 
 217     public void setDocCommentTree(Element element, List<? extends DocTree> fullBody,
 218                                   List<? extends DocTree> blockTags, Utils utils) {
 219         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags);
 220         dcTreesMap.put(element, new DocCommentDuo(null, docTree));
 221         // A method having null comment (no comment) that might need to be replaced
 222         // with a synthetic comment, remove such a comment from the cache.
 223         utils.removeCommentHelper(element);
 224     }
 225 
 226     public void setAccessorCommentTree(Element element, List<DocTree> fullBody,
 227                                   List<DocTree> blockTags, Utils utils) {
 228         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags);
 229         TreePath pathToEncl = utils.docTrees.getPath(element.getEnclosingElement());
 230         dcTreesMap.put(element, new DocCommentDuo(pathToEncl, docTree));
 231         // There maybe an entry with the original comments usually null,
 232         // therefore remove that entry if it exists, and allow a new one
 233         // to be reestablished.
 234         utils.removeCommentHelper(element);
 235     }
 236 
 237     /**
 238      * A simplistic container to transport a TreePath, DocCommentTree pair.
 239      * Here is why we need this:
 240      * a. not desirable to add javac's pair.
 241      * b. DocTreePath is not a viable  option either, as a null TreePath is required
 242      * to represent synthetic comments for Enum.values, valuesOf, javafx properties.
 243      */
 244     public static class DocCommentDuo {
 245         public final TreePath treePath;
 246         public final DocCommentTree dcTree;
 247 
 248         public DocCommentDuo(TreePath treePath, DocCommentTree dcTree) {
 249             this.treePath = treePath;
 250             this.dcTree = dcTree;
 251         }
 252     }
 253 }