1 /*
2  * Copyright (c) 2001, 2019, 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 package jdk.javadoc.internal.doclets.toolkit.taglets;
27 
28 import java.util.EnumSet;
29 import java.util.List;
30 import java.util.Set;
31 
32 import javax.lang.model.element.Element;
33 
34 import com.sun.source.doctree.DocTree;
35 import jdk.javadoc.doclet.Taglet.Location;
36 
37 import jdk.javadoc.internal.doclets.toolkit.Content;
38 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
39 import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
40 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
41 
42 /**
43  * A simple single argument custom tag.
44  *
45  *  <p><b>This is NOT part of any supported API.
46  *  If you write code that depends on this, you do so at your own risk.
47  *  This code and its internal interfaces are subject to change or
48  *  deletion without notice.</b>
49  */
50 
51 public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
52 
53     /**
54      * The header to output.
55      */
56     protected String header;
57 
58     /**
59      * Whether or not the taglet should generate output.
60      * Standard tags like at-author, at-since, at-version can be disabled
61      * by command-line options; custom tags created with -tag can be
62      * disabled with an X in the defining string.
63      */
64     protected final boolean enabled;
65 
66     /**
67      * Constructs a {@code SimpleTaglet}.
68      *
69      * @param tagName   the name of this tag
70      * @param header    the header to output
71      * @param locations the possible locations that this tag can appear in
72      *                  The string can contain 'p' for package, 't' for type,
73      *                  'm' for method, 'c' for constructor and 'f' for field.
74      *                  See {@linbk #getLocations(String) getLocations} for the
75      *                  complete list.
76      */
SimpleTaglet(String tagName, String header, String locations)77     public SimpleTaglet(String tagName, String header, String locations) {
78         this(tagName, header, getLocations(locations), isEnabled(locations));
79     }
80 
81     /**
82      * Constructs a {@code SimpleTaglet}.
83      *
84      * @param tagKind   the kind of this tag
85      * @param header    the header to output
86      * @param locations the possible locations that this tag can appear in.
87      */
SimpleTaglet(DocTree.Kind tagKind, String header, Set<Location> locations)88     public SimpleTaglet(DocTree.Kind tagKind, String header, Set<Location> locations) {
89         this(tagKind, header, locations, true);
90     }
91 
92 
93     /**
94      * Constructs a {@code SimpleTaglet}.
95      *
96      * @param tagName   the name of this tag
97      * @param header    the header to output.
98      * @param locations the possible locations that this tag can appear in
99      */
SimpleTaglet(String tagName, String header, Set<Location> locations)100     public SimpleTaglet(String tagName, String header, Set<Location> locations) {
101         this(tagName, header, locations, true);
102     }
103 
104     /**
105      * Constructs a {@code SimpleTaglet}.
106      *
107      * @param tagName   the name of this tag
108      * @param header    the header to output.
109      * @param locations the possible locations that this tag can appear in
110      */
SimpleTaglet(String tagName, String header, Set<Location> locations, boolean enabled)111     public SimpleTaglet(String tagName, String header, Set<Location> locations, boolean enabled) {
112         super(tagName, false, locations);
113         this.header = header;
114         this.enabled = enabled;
115     }
116 
117     /**
118      * Constructs a {@code SimpleTaglet}.
119      *
120      * @param tagKind   the kind of this tag
121      * @param header    the header to output.
122      * @param locations the possible locations that this tag can appear in
123      */
SimpleTaglet(DocTree.Kind tagKind, String header, Set<Location> locations, boolean enabled)124     public SimpleTaglet(DocTree.Kind tagKind, String header, Set<Location> locations, boolean enabled) {
125         super(tagKind, false, locations);
126         this.header = header;
127         this.enabled = enabled;
128     }
129 
getLocations(String locations)130     private static Set<Location> getLocations(String locations) {
131         Set<Location> set = EnumSet.noneOf(Location.class);
132         for (int i = 0; i < locations.length(); i++) {
133             switch (locations.charAt(i)) {
134                 case 'a':  case 'A':
135                     return EnumSet.allOf(Location.class);
136                 case 'c':  case 'C':
137                     set.add(Location.CONSTRUCTOR);
138                     break;
139                 case 'f':  case 'F':
140                     set.add(Location.FIELD);
141                     break;
142                 case 'm':  case 'M':
143                     set.add(Location.METHOD);
144                     break;
145                 case 'o':  case 'O':
146                     set.add(Location.OVERVIEW);
147                     break;
148                 case 'p':  case 'P':
149                     set.add(Location.PACKAGE);
150                     break;
151                 case 's':  case 'S':        // super-packages, anyone?
152                     set.add(Location.MODULE);
153                     break;
154                 case 't':  case 'T':
155                     set.add(Location.TYPE);
156                     break;
157                 case 'x':  case 'X':
158                     break;
159             }
160         }
161         return set;
162     }
163 
isEnabled(String locations)164     private static boolean isEnabled(String locations) {
165         return locations.matches("[^Xx]*");
166     }
167 
168     @Override
inherit(DocFinder.Input input, DocFinder.Output output)169     public void inherit(DocFinder.Input input, DocFinder.Output output) {
170         List<? extends DocTree> tags = input.utils.getBlockTags(input.element, this);
171         if (!tags.isEmpty()) {
172             output.holder = input.element;
173             output.holderTag = tags.get(0);
174             CommentHelper ch = input.utils.getCommentHelper(output.holder);
175             output.inlineTags = input.isFirstSentence
176                     ? ch.getFirstSentenceTrees(output.holderTag)
177                     : ch.getTags(output.holderTag);
178         }
179     }
180 
181     @Override
getTagletOutput(Element element, DocTree tag, TagletWriter writer)182     public Content getTagletOutput(Element element, DocTree tag, TagletWriter writer) {
183         return header == null || tag == null ? null : writer.simpleTagOutput(element, tag, header);
184     }
185 
186     @Override
getTagletOutput(Element holder, TagletWriter writer)187     public Content getTagletOutput(Element holder, TagletWriter writer) {
188         Utils utils = writer.configuration().utils;
189         List<? extends DocTree> tags = utils.getBlockTags(holder, this);
190         if (header == null || tags.isEmpty()) {
191             return null;
192         }
193         return writer.simpleTagOutput(holder, tags, header);
194     }
195 }
196