1 /*
2  * Copyright (c) 1997, 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 package com.sun.tools.javadoc.main;
27 
28 import java.io.DataInputStream;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.text.CollationKey;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34 
35 import javax.tools.FileObject;
36 
37 import com.sun.javadoc.*;
38 import com.sun.source.util.TreePath;
39 import com.sun.tools.javac.tree.JCTree;
40 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
41 import com.sun.tools.javac.util.Position;
42 
43 /**
44  * abstract base class of all Doc classes.  Doc item's are representations
45  * of java language constructs (class, package, method,...) which have
46  * comments and have been processed by this run of javadoc.  All Doc items
47  * are unique, that is, they are == comparable.
48  *
49  *  <p><b>This is NOT part of any supported API.
50  *  If you write code that depends on this, you do so at your own risk.
51  *  This code and its internal interfaces are subject to change or
52  *  deletion without notice.</b>
53  *
54  * @since 1.2
55  * @author Robert Field
56  * @author Atul M Dambalkar
57  * @author Neal Gafter (rewrite)
58  */
59 @Deprecated(since="9", forRemoval=true)
60 @SuppressWarnings("removal")
61 public abstract class DocImpl implements Doc, Comparable<Object> {
62 
63     /**
64      * Doc environment
65      */
66     protected final DocEnv env;   //### Rename this everywhere to 'docenv' ?
67 
68     /**
69      * Back pointer to the tree node for this doc item.
70      * May be null if there is no associated tree.
71      */
72     protected TreePath treePath;
73 
74     /**
75      *  The complex comment object, lazily initialized.
76      */
77     private Comment comment;
78 
79     /**
80      * The cached sort key, to take care of Natural Language Text sorting.
81      */
82     private CollationKey collationkey = null;
83 
84     /**
85      *  Raw documentation string.
86      */
87     protected String documentation;  // Accessed in PackageDocImpl, RootDocImpl
88 
89     /**
90      * Cached first sentence.
91      */
92     private Tag[] firstSentence;
93 
94     /**
95      * Cached inline tags.
96      */
97     private Tag[] inlineTags;
98 
99     /**
100      * Constructor.
101      */
DocImpl(DocEnv env, TreePath treePath)102     DocImpl(DocEnv env, TreePath treePath) {
103         this.treePath = treePath;
104         this.documentation = getCommentText(treePath);
105         this.env = env;
106     }
107 
getCommentText(TreePath p)108     private static String getCommentText(TreePath p) {
109         if (p == null)
110             return null;
111 
112         JCCompilationUnit topLevel = (JCCompilationUnit) p.getCompilationUnit();
113         JCTree tree = (JCTree) p.getLeaf();
114         return topLevel.docComments.getCommentText(tree);
115     }
116 
117     /**
118      * So subclasses have the option to do lazy initialization of
119      * "documentation" string.
120      */
documentation()121     protected String documentation() {
122         if (documentation == null) documentation = "";
123         return documentation;
124     }
125 
126     /**
127      * For lazy initialization of comment.
128      */
comment()129     Comment comment() {
130         if (comment == null) {
131             String d = documentation();
132             if (env.javaScriptScanner != null) {
133                 env.javaScriptScanner.parse(d, new JavaScriptScanner.Reporter() {
134                     @Override
135                     public void report() {
136                         env.error(DocImpl.this, "javadoc.JavaScript_in_comment");
137                         throw new Error();
138                     }
139                 });
140             }
141             if (env.doclint != null
142                     && treePath != null
143                     && env.shouldCheck(treePath.getCompilationUnit())
144                     && d.equals(getCommentText(treePath))) {
145                 env.doclint.scan(treePath);
146             }
147             comment = new Comment(this, d);
148         }
149         return comment;
150     }
151 
152     /**
153      * Return the text of the comment for this doc item.
154      * TagImpls have been removed.
155      */
commentText()156     public String commentText() {
157         return comment().commentText();
158     }
159 
160     /**
161      * Return all tags in this Doc item.
162      *
163      * @return an array of TagImpl containing all tags on this Doc item.
164      */
tags()165     public Tag[] tags() {
166         return comment().tags();
167     }
168 
169     /**
170      * Return tags of the specified kind in this Doc item.
171      *
172      * @param tagname name of the tag kind to search for.
173      * @return an array of TagImpl containing all tags whose 'kind()'
174      * matches 'tagname'.
175      */
tags(String tagname)176     public Tag[] tags(String tagname) {
177         return comment().tags(tagname);
178     }
179 
180     /**
181      * Return the see also tags in this Doc item.
182      *
183      * @return an array of SeeTag containing all &#64;see tags.
184      */
seeTags()185     public SeeTag[] seeTags() {
186         return comment().seeTags();
187     }
188 
inlineTags()189     public Tag[] inlineTags() {
190         if (inlineTags == null) {
191             inlineTags = Comment.getInlineTags(this, commentText());
192         }
193         return inlineTags;
194     }
195 
firstSentenceTags()196     public Tag[] firstSentenceTags() {
197         if (firstSentence == null) {
198             //Parse all sentences first to avoid duplicate warnings.
199             inlineTags();
200             try {
201                 env.setSilent(true);
202                 firstSentence = Comment.firstSentenceTags(this, commentText());
203             } finally {
204                 env.setSilent(false);
205             }
206         }
207         return firstSentence;
208     }
209 
210     /**
211      * Utility for subclasses which read HTML documentation files.
212      */
readHTMLDocumentation(InputStream input, FileObject filename)213     String readHTMLDocumentation(InputStream input, FileObject filename) throws IOException {
214         byte[] filecontents = new byte[input.available()];
215         try {
216             DataInputStream dataIn = new DataInputStream(input);
217             dataIn.readFully(filecontents);
218         } finally {
219             input.close();
220         }
221         String encoding = env.getEncoding();
222         String rawDoc = (encoding!=null)
223             ? new String(filecontents, encoding)
224             : new String(filecontents);
225         Pattern bodyPat = Pattern.compile("(?is).*<body\\b[^>]*>(.*)</body\\b.*");
226         Matcher m = bodyPat.matcher(rawDoc);
227         if (m.matches()) {
228             return m.group(1);
229         } else {
230             String key = rawDoc.matches("(?is).*<body\\b.*")
231                     ? "javadoc.End_body_missing_from_html_file"
232                     : "javadoc.Body_missing_from_html_file";
233             env.error(SourcePositionImpl.make(filename, Position.NOPOS, null), key);
234             return "";
235         }
236     }
237 
238     /**
239      * Return the full unprocessed text of the comment.  Tags
240      * are included as text.  Used mainly for store and retrieve
241      * operations like internalization.
242      */
getRawCommentText()243     public String getRawCommentText() {
244         return documentation();
245     }
246 
247     /**
248      * Set the full unprocessed text of the comment.  Tags
249      * are included as text.  Used mainly for store and retrieve
250      * operations like internalization.
251      */
setRawCommentText(String rawDocumentation)252     public void setRawCommentText(String rawDocumentation) {
253         treePath = null;
254         documentation = rawDocumentation;
255         comment = null;
256     }
257 
258     /**
259      * Set the full unprocessed text of the comment and tree path.
260      */
setTreePath(TreePath treePath)261     void setTreePath(TreePath treePath) {
262         this.treePath = treePath;
263         documentation = getCommentText(treePath);
264         comment = null;
265     }
266 
267     /**
268      * return a key for sorting.
269      */
key()270     CollationKey key() {
271         if (collationkey == null) {
272             collationkey = generateKey();
273         }
274         return collationkey;
275     }
276 
277     /**
278      * Generate a key for sorting.
279      * <p>
280      * Default is name().
281      */
generateKey()282     CollationKey generateKey() {
283         String k = name();
284         // System.out.println("COLLATION KEY FOR " + this + " is \"" + k + "\"");
285         return env.doclocale.collator.getCollationKey(k);
286     }
287 
288     /**
289      * Returns a string representation of this Doc item.
290      */
291     @Override
toString()292     public String toString() {
293         return qualifiedName();
294     }
295 
296     /**
297      * Returns the name of this Doc item.
298      *
299      * @return  the name
300      */
name()301     public abstract String name();
302 
303     /**
304      * Returns the qualified name of this Doc item.
305      *
306      * @return  the name
307      */
qualifiedName()308     public abstract String qualifiedName();
309 
310     /**
311      * Compares this Object with the specified Object for order.  Returns a
312      * negative integer, zero, or a positive integer as this Object is less
313      * than, equal to, or greater than the given Object.
314      * <p>
315      * Included so that Doc item are java.lang.Comparable.
316      *
317      * @param   obj the {@code Object} to be compared.
318      * @return  a negative integer, zero, or a positive integer as this Object
319      *          is less than, equal to, or greater than the given Object.
320      * @exception ClassCastException the specified Object's type prevents it
321      *            from being compared to this Object.
322      */
compareTo(Object obj)323     public int compareTo(Object obj) {
324         // System.out.println("COMPARE \"" + this + "\" to \"" + obj + "\" = " + key().compareTo(((DocImpl)obj).key()));
325         return key().compareTo(((DocImpl)obj).key());
326     }
327 
328     /**
329      * Is this Doc item a field?  False until overridden.
330      *
331      * @return true if it represents a field
332      */
isField()333     public boolean isField() {
334         return false;
335     }
336 
337     /**
338      * Is this Doc item an enum constant?  False until overridden.
339      *
340      * @return true if it represents an enum constant
341      */
isEnumConstant()342     public boolean isEnumConstant() {
343         return false;
344     }
345 
346     /**
347      * Is this Doc item a constructor?  False until overridden.
348      *
349      * @return true if it represents a constructor
350      */
isConstructor()351     public boolean isConstructor() {
352         return false;
353     }
354 
355     /**
356      * Is this Doc item a method (but not a constructor or annotation
357      * type element)?
358      * False until overridden.
359      *
360      * @return true if it represents a method
361      */
isMethod()362     public boolean isMethod() {
363         return false;
364     }
365 
366     /**
367      * Is this Doc item an annotation type element?
368      * False until overridden.
369      *
370      * @return true if it represents an annotation type element
371      */
isAnnotationTypeElement()372     public boolean isAnnotationTypeElement() {
373         return false;
374     }
375 
376     /**
377      * Is this Doc item a interface (but not an annotation type)?
378      * False until overridden.
379      *
380      * @return true if it represents a interface
381      */
isInterface()382     public boolean isInterface() {
383         return false;
384     }
385 
386     /**
387      * Is this Doc item a exception class?  False until overridden.
388      *
389      * @return true if it represents a exception
390      */
isException()391     public boolean isException() {
392         return false;
393     }
394 
395     /**
396      * Is this Doc item a error class?  False until overridden.
397      *
398      * @return true if it represents a error
399      */
isError()400     public boolean isError() {
401         return false;
402     }
403 
404     /**
405      * Is this Doc item an enum type?  False until overridden.
406      *
407      * @return true if it represents an enum type
408      */
isEnum()409     public boolean isEnum() {
410         return false;
411     }
412 
413     /**
414      * Is this Doc item an annotation type?  False until overridden.
415      *
416      * @return true if it represents an annotation type
417      */
isAnnotationType()418     public boolean isAnnotationType() {
419         return false;
420     }
421 
422     /**
423      * Is this Doc item an ordinary class (i.e. not an interface,
424      * annotation type, enumeration, exception, or error)?
425      * False until overridden.
426      *
427      * @return true if it represents an ordinary class
428      */
isOrdinaryClass()429     public boolean isOrdinaryClass() {
430         return false;
431     }
432 
433     /**
434      * Is this Doc item a class
435      * (and not an interface or annotation type)?
436      * This includes ordinary classes, enums, errors and exceptions.
437      * False until overridden.
438      *
439      * @return true if it represents a class
440      */
isClass()441     public boolean isClass() {
442         return false;
443     }
444 
445     /**
446      * return true if this Doc is include in the active set.
447      */
isIncluded()448     public abstract boolean isIncluded();
449 
450     /**
451      * Return the source position of the entity, or null if
452      * no position is available.
453      */
position()454     public SourcePosition position() { return null; }
455 }
456