001package Torello.JavaDoc;
002
003
004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
005// Standard-Java Imports
006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
007
008import java.util.*;
009
010import java.io.IOException;
011import java.util.function.Consumer;
012
013
014// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
015// Java-HTML Imports
016// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
017
018import Torello.Java.*;
019
020import static Torello.Java.C.*;
021import static Torello.JavaDoc.PF.*;
022
023import Torello.Java.ReadOnly.ReadOnlyList;
024import Torello.Java.ReadOnly.ReadOnlyArrayList;
025import Torello.Java.ReadOnly.ROArrayListBuilder;
026import Torello.Java.Additional.Ret2;
027
028
029// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
030// JDUInternal
031// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
032
033import Torello.JDUInternal.Annotations.EntityAnnotations.Mirror.EntityAnnotationMirrors;
034import Torello.JDUInternal.Annotations.EntityAnnotations.EntityAnnotationData;
035
036import Torello.JDUInternal.Parse.Java.Location.LocationBuilder1;
037import Torello.JDUInternal.Parse.Java.Location.LocationBuilder2;
038
039// NOTE: Here is the Code that uses LocationBuilder1 and 2...  It tells you which of the two
040//       is applied, and when, and why...
041//
042// this.location = (entity == Entity.INNER_CLASS)
043//      ? LocationBuilder2.build(util, tree, util.getJavaDocCommentTree(tree))
044//      : LocationBuilder1.build(...)
045
046
047// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
048// The new Source-Code Parser: com.sun.source.*
049// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
050
051import com.sun.source.util.*;
052import com.sun.source.tree.*;
053import com.sun.source.doctree.*;
054
055
056/**
057 * <B CLASS=JDDescLabel>Reflection Class:</B>
058 * 
059 * <BR />Common-Root Ancestor Class of all Bridge Data-Classes.
060 * 
061 * <BR /><BR />
062 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DECLARATION>
063 */
064@JDHeaderBackgroundImg
065public abstract class Declaration implements java.io.Serializable
066{
067    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
068    public static final long serialVersionUID = 1;
069
070    /**
071     * For the purposes of passing these around to different parts of the code, every one of these
072     * are given a unique ID.  This id is unique for a method, whether it was parsed from a detail
073     * or a summary section.  This id is (probably) not useful outside of the HTML Processor
074     * Classes.
075     * 
076     * <BR /><BR /><B CLASS=JDDescLabel>ID Clone:</B>
077     * 
078     * <BR />If a subclass of {@code Declaration} is cloned, then this {@code id} field is also
079     * cloned / copied.
080     */
081    public final int id;
082
083    // The id is just created using this counter.
084    private static int idCounter = 1;
085
086    // Used for Modifiers and other Empty ReadOnlyLists's of String
087    static final ReadOnlyList<String> EMPTY_READONLY_LIST = ReadOnlyList.of();
088
089    /**
090     * This returns the {@code String} that is to be sent to the Syntax {@link HiLiter}.  This is
091     * the code inserted into the "HiLited Code" Part (at the end) of a Details Entry on a Java-Doc
092     * Web Page.
093     * 
094     * <BR /><BR />On the part of a Java-Doc Web-Page having a "Method Detail", the Method's
095     * HiLited Source-Code body is obtained by the Upgrader-Logic using this here method.
096     * 
097     * <BR /><BR /><B CLASS=JDDescLabel>Sub-Class Return Values:</B>
098     * 
099     * <BR />This method is overloaded by all sub-classes, and returns values as follows:
100     * 
101     * <BR /><BR /><UL CLASS=JDUL>
102     * <LI>{@link Method} will return its {@link Callable#body} field.</LI>
103     * <LI>{@link Constructor} will return its {@link Callable#body} field.</LI>
104     * <LI>{@link Field} will return the {@link #signature} field</LI>
105     * <LI>{@link EnumConstant} will return the {@link #signature} field</LI>
106     * <LI>{@link AnnotationElem} will return the {@link #signature} field</LI>
107     * <LI>{@link NestedType} will always return null</LI>
108     * </UL>
109     * 
110     * @return The {@code String} that is ultimately sent to the Syntax HiLiter, and inserted
111     * into a Java Doc page.
112     * 
113     * This is package-private, and isn't useful enough to put into the API - this is used
114     * internally, only.
115     */
116    abstract String codeHiLiteString();
117
118    // Package-Private.  This only processes Java-Doc Upgrader Annotations.  Any other Annotations
119    // which are placed on a Detail-Element can be found in:
120    //
121    // public ReadOnlyList<String> annotations
122    //
123    // However, they will just be the "Raw Sting" version of the Annotation.  No More, No Less
124
125    public final EntityAnnotationMirrors jduAnnotationMirrors;
126
127
128    // ********************************************************************************************
129    // ********************************************************************************************
130    // Basic String-Fields
131    // ********************************************************************************************
132    // ********************************************************************************************
133
134
135    /**
136     * The <B>Name</B> of the java {@link Field}, {@link Method}, {@code Constructor},
137     * {@link EnumConstant} or {@link AnnotationElem}.  This will be a <B>simple, standard</B>
138     * 'Java Identifier'.
139     * 
140     * <BR /><BR />Note that the name of a {@code Constructor} (for-example) is always just the
141     * name of the class.
142     * 
143     * <BR /><BR />This field will never be null.
144     */
145    public final String name;
146
147    /**
148     * The complete, declared <B>Signature</B> (as a {@code String}) of the {@link Method},
149     * {@link Field}, {@link Constructor}, {@link EnumConstant} or {@link AnnotationElem}.
150     * 
151     * <BR /><BR />This field would never be null.
152     */
153    public final String signature;
154
155    /**
156     * The <B>Java Doc Comment</B> of this <B>'{@link Entity}'</B> ({@link Field}, {@link Method},
157     * {@code Constructor}, {@link EnumConstant}, {@link AnnotationElem} or {@link NestedType}) as
158     * a {@code String} - if one exists.  The Java Doc Comment is the one defined directly above
159     * the {@code Declaration}.
160     * 
161     * <BR /><BR />If this <CODE>Entity</CODE> / Member ({@code Field, Method, Constructor} etc...)
162     * did not have a Java Doc Comment placed on it, <I>then this field {@code 'jdComment'} will be
163     * {@code null}.</I>
164     */
165    public final String jdComment;
166
167    /**
168     * The <B>Body</B> of this <B>'{@link Entity}'</B> ({@link Field}, {@link Method},
169     * {@code Constructor}, {@link EnumConstant}, {@link AnnotationElem} or {@link NestedType}) as
170     * a {@code String} - if one exists.  
171     * 
172     * <BR /><BR />If this <CODE>Entity</CODE> / Member ({@code Field, Method, Constructor} etc...)
173     * did not have a body, <I>then this field {@code 'body'} will be {@code null}.</I>
174     * 
175     * <BR /><BR />The {@code 'body'} of a {@code Method} or {@code Constructor} is exactly the
176     * code that comprises it.  If the method is {@code abstract}, then the method will not have a
177     * body, and in such cases this field will be null.  If this member / entity is a {@link Field}
178     * then the body is the initializer of the {@code Field}.  Again, if there were no initializer
179     * for the field, then {@code 'body'} would also be null.
180     */
181    public final String body;
182
183
184    // ********************************************************************************************
185    // ********************************************************************************************
186    // Non-Basic Fields
187    // ********************************************************************************************
188    // ********************************************************************************************
189
190
191    /**
192     * This just stores the type of {@link Entity} this is.  For sub-classes instances of
193     * {@link Declaration} which are {@link Method}, this field will be equal to
194     * {@link Entity#METHOD}.  For instances of the {@link Field} sub-class, this will equal
195     * {@link Entity#FIELD}, and so on and so forth.
196     * 
197     * <BR /><BR />Mostly, this makes code easier to read when used along-side <B>if-statements</B>
198     * or <B>switch-statements</B>.  This field somewhat akin to {@code Declaration.getClass()}
199     * (when retrieving the specific {@code Declaration} sub-class type).
200     * 
201     * <BR /><BR /><B CLASS=JDDescLabel>Reminder:</B>
202     * 
203     * <BR />Both this class, and sub-class {@code Callable} are declared {@code abstract}, and
204     * only instances of Method, Field, Constructor, etc... can be instantiated.  Only
205     * non-{@code abstract} implementations of this class need to worry about assigning this field
206     * to any real-value.
207     */
208    public final Entity entity;
209
210    /** Location instance that contains character-locations within the original Java Source-File */
211    public final Location location;
212
213
214    // ********************************************************************************************
215    // ********************************************************************************************
216    // ReadOnlyList<String> Fields
217    // ********************************************************************************************
218    // ********************************************************************************************
219
220
221    /**
222     * The {@code 'modifiers'} placed on this {@code Declaration}, including {@code String's}
223     * such as: {@code public, static, final} etc...
224     */
225    public ReadOnlyList<String> modifiers;
226
227    /** <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DECL_ANNOT> */
228    public ReadOnlyList<String> annotations;
229
230
231    // ********************************************************************************************
232    // ********************************************************************************************
233    // Constructor - com.sun.source.tree 
234    // ********************************************************************************************
235    // ********************************************************************************************
236
237
238    // package-private: Only used by subclasses.
239    Declaration(
240            final EntityAnnotationData  ead,
241            final TreeUtils             util,
242            final Tree                  tree,
243            final ModifiersTree         mt,
244            final String                name,
245            final Entity                entity,
246            final Tree                  body
247        )
248    {
249        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
250        // Pre-Liminary
251        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
252
253        this.id                 = idCounter++;
254        this.name               = name;
255        this.entity             = entity;
256
257
258        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
259        // The Annotations Placed on this Declaration
260        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
261        //
262        // NOTE: For EnumConstant's, the passed Modifiers-Tree is just null!
263
264        // List<? extends AnnotationTree> annotList = ...
265        @SuppressWarnings("unchecked")
266        final List<AnnotationTree> annotList = (mt == null)
267            ? null
268            : (List<AnnotationTree>) mt.getAnnotations();
269
270        if ((annotList == null) || (annotList.size() == 0))
271            this.annotations = EMPTY_READONLY_LIST;
272
273        else this.annotations = new ReadOnlyArrayList<String>
274            (annotList, (AnnotationTree at) -> at.toString().trim(), annotList.size());
275
276
277        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
278        // The Modifiers that Flag this Declaration (private, public, static, final, etc...)
279        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
280        //
281        // NOTE: For EnumConstant's, the passed Modifiers-Tree is just null!
282
283        final Set<javax.lang.model.element.Modifier> modSet = (mt == null)
284            ? null
285            : mt.getFlags();
286
287        if ((modSet == null) || (modSet.size() == 0))
288            this.modifiers = EMPTY_READONLY_LIST;
289
290        else this.modifiers = new ReadOnlyArrayList<String>
291            (modSet, (javax.lang.model.element.Modifier m) -> m.toString().trim(), modSet.size());
292
293
294        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
295        // Location
296        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
297
298        this.location = (entity == Entity.INNER_CLASS)
299
300            ? LocationBuilder2.build(util, tree, util.getJavaDocCommentTree(tree))
301
302            : LocationBuilder1.build(
303                util, tree, util.getJavaDocCommentTree(tree), body,
304                (entity == Entity.FIELD) ? body : null
305            );
306
307
308        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
309        // Now the String's
310        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
311
312        this.signature = util.srcFileAsStr.substring
313            (this.location.signatureStartPos, this.location.signatureEndPos);
314
315        this.jdComment = (this.location.jdcStartPos == -1)
316            ? null
317            : util.srcFileAsStr.substring(this.location.jdcStartPos, this.location.jdcEndPos);
318
319        this.body = (this.location.bodyStartPos == -1)
320            ? null
321            : util.srcFileAsStr.substring(this.location.bodyStartPos, this.location.bodyEndPos);
322
323
324        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
325        // The JavaDoc-Upgrader SPECIFIC Annotations.  These are handled & Processed by JDU
326        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
327
328        if ((annotList == null) || (annotList.size() == 0))
329            this.jduAnnotationMirrors = EntityAnnotationMirrors.EMPTY_MIRROR;
330
331
332        // Because `this.signature` is passed to this constructor, this whole invocation has to be
333        // at the end of the method, instead of above - where the annotations were processed!
334        // 
335        // NOTE: The `annotList` variable was created way above, at the top of this constructor!
336
337        else this.jduAnnotationMirrors = (entity != Entity.INNER_CLASS)
338            ? new EntityAnnotationMirrors(annotList, this.signature, ead)
339            : EntityAnnotationMirrors.EMPTY_MIRROR;
340    }
341
342
343    // ********************************************************************************************
344    // ********************************************************************************************
345    // Constructor - synthetic methods
346    // ********************************************************************************************
347    // ********************************************************************************************
348
349
350    // Used only by the Callable Subclass, for building instances of derived/synthetic methods
351    // and constructors.  (For instance, an enum has 'valueOf()' and 'values()')
352    // These methods do not have a location or a jdComment or even a body to hilite
353
354    Declaration(String name, Entity entity, String signature)
355    {
356        this.id                     = idCounter++;
357        this.name                   = name;
358        this.entity                 = entity;
359        this.modifiers              = EMPTY_READONLY_LIST;
360        this.annotations            = EMPTY_READONLY_LIST;
361        this.signature              = signature;
362        this.jduAnnotationMirrors   = EntityAnnotationMirrors.EMPTY_MIRROR;
363
364        // Since this constructor is only used for "Synthetic Methods" (barely ever used), it is no
365        // big deal to just assign these null;
366
367        this.location   = null;
368        this.jdComment  = null;
369        this.body       = null;
370    }
371
372    // Not private - used by sub-classes
373    Declaration(Declaration d)
374    {
375        this.id                     = d.id;
376        this.annotations            = d.annotations;
377        this.modifiers              = d.modifiers;
378        this.name                   = d.name;
379        this.signature              = d.signature;
380        this.jdComment              = d.jdComment;
381        this.body                   = d.body;
382        this.entity                 = d.entity;
383        this.location               = d.location;
384        this.jduAnnotationMirrors   = d.jduAnnotationMirrors;
385    }
386
387
388    // ********************************************************************************************
389    // ********************************************************************************************
390    // Package-Private toString-HELPERS: Used by all subclasses 'toString(int flags)' methods
391    // ********************************************************************************************
392    // ********************************************************************************************
393
394
395    Ret2<Boolean, Boolean> jowFlags(int flags)
396    {
397        boolean onlyJOW         = (flags & JOW_INSTEAD) > 0;
398        boolean addJOW          = (flags & JOW_ALSO) > 0;
399
400        // "onlyJOW" has a higher FLAG-PRECEDENCY
401        if (onlyJOW && addJOW) addJOW = false;
402
403        return new Ret2<>(addJOW, onlyJOW);
404    }
405
406    String printedName(String entity, int numSpaces, boolean color)
407    {
408        return
409            StringParse.rightSpacePad(entity + " Name:", numSpaces) +
410            "[" + (color ? BCYAN : "") + name + (color ? RESET : "") + "]\n";
411    }
412
413    String printedSignature(int numSpaces, boolean color)
414    {
415        return
416            StringParse.rightSpacePad("Signature:", numSpaces) +
417            "[" + (color ? BYELLOW : "") +
418            StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) +
419            (color ? RESET : "") + "]\n";
420    }
421
422    String printedDeclaration(int numSpaces, boolean color)
423    {
424        return
425            StringParse.rightSpacePad("Declaration:", numSpaces) +
426            "[" + (color ? BYELLOW : "") +
427            StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) +
428            (color ? RESET : "") + "]\n";
429    }
430
431    String printedModifiers(int numSpaces)
432    {
433        return
434            StringParse.rightSpacePad("Modifiers:", numSpaces) +
435            "[" + StrCSV.toCSV(modifiers, true, true, null) + "]\n";
436    }
437
438    String printedComments(int numSpaces, boolean color, boolean comments)
439    {
440        if (! comments)
441            return "";
442
443        else if (jdComment == null) return
444            "\n" +
445            StringParse.rightSpacePad("JD Comments:", numSpaces) +
446            (color ? BRED : "") + "None Available / Not Included" + (color ? RESET : "");
447
448        else return
449            "\n" +
450            StringParse.rightSpacePad("JD Comments:", numSpaces) +
451            "[" +
452            (color ? BGREEN : "") +
453            StrPrint.abbrevEndRDSF(jdComment, MAX_STR_LEN, true) +
454            (color ? RESET : "") +
455            "]";
456    }
457
458    // NOTE: This is always the last item printed to the output-string.  This line *DOES NOT* end
459    //       with a new-line '\n' character.
460
461    String printedLocation(int numSpaces, boolean color, boolean briefLocation)
462    {
463        if (location == null) return StringParse.rightSpacePad("Location:", numSpaces) + "null";
464
465        if (briefLocation) return color
466            ?
467                (StringParse.rightSpacePad("Location:", numSpaces) +
468                "[" +
469                "signature-line=" + BRED + this.location.signatureStartLine + RESET + ", " +
470                "javadoc-line=" + BRED + this.location.jdcStartLine + RESET + ", " +
471                "body-line=" + BRED + this.location.bodyStartLine + RESET +
472                "]")
473            :
474                (StringParse.rightSpacePad("Location:", numSpaces) +
475                "[" +
476                "signature-line=" + this.location.signatureStartLine + ", " +
477                "javadoc-line=" + this.location.jdcStartLine + ", " +
478                "body-line=" + this.location.bodyStartLine +
479                ']');
480
481        String spaces = StringParse.nChars(' ', numSpaces);
482
483        if (color) return
484            StringParse.rightSpacePad("Location:", numSpaces) +
485            "JavaDocComment: [" +
486                "startPos=" + BRED + location.jdcStartPos + RESET + ", " +
487                "endPos=" + BRED + location.jdcEndPos + RESET + ", " +
488                "startLine=" + BRED + location.jdcStartLine + RESET + ", " +
489                "endLine=" + BRED + location.jdcEndLine + RESET + ", " +
490                "startCol=" + BRED + location.jdcStartCol + RESET + ", " +
491                "endCol=" + BRED + location.jdcEndCol + RESET + "]\n" +
492
493            spaces + "Signature:      [" +
494                "startPos=" + BRED + location.signatureStartPos + RESET + ", " +
495                "endPos=" + BRED + location.signatureEndPos + RESET + ", " +
496                "startLine=" + BRED + location.signatureStartLine + RESET + ", " +
497                "endLine=" + BRED + location.signatureEndLine + RESET + ", " +
498                "startCol=" + BRED + location.signatureStartCol + RESET + ", " +
499                "endCol=" + BRED + location.signatureEndCol + RESET + "]\n" +
500
501            spaces + "Body:           [" +
502                "startPos=" + BRED + location.bodyStartPos + RESET + ", " +
503                "endPos=" + BRED + location.bodyEndPos + RESET + ", " +
504                "startLine=" + BRED + location.bodyStartLine + RESET + ", " +
505                "endLine=" + BRED + location.bodyEndLine + RESET + ", " +
506                "startCol=" + BRED + location.bodyStartCol + RESET + ", " +
507                "endCol=" + BRED + location.bodyEndCol + RESET + "]";
508
509        else return
510            StringParse.rightSpacePad("Location:", numSpaces) +
511            "JavaDocComment: [" +
512                "startPos=" + location.jdcStartPos + ", " +
513                "endPos=" + location.jdcEndPos + ", " +
514                "startLine=" + location.jdcStartLine + ", " +
515                "endLine=" + location.jdcEndLine + ", " +
516                "startCol=" + location.jdcStartCol + ", " +
517                "endCol=" + location.jdcEndCol + "]\n" +
518
519            spaces + "Signature:      [" +
520                "startPos=" + location.signatureStartPos + ", " +
521                "endPos=" + location.signatureEndPos + ", " +
522                "startLine=" + location.signatureStartLine + ", " +
523                "endLine=" + location.signatureEndLine + ", " +
524                "startCol=" + location.signatureStartCol + ", " +
525                "endCol=" + location.signatureEndCol + "]\n" +
526
527            spaces + "Body:           [" +
528                "startPos=" + location.bodyStartPos + ", " +
529                "endPos=" + location.bodyEndPos + ", " +
530                "startLine=" + location.bodyStartLine + ", " +
531                "endLine=" + location.bodyEndLine + ", " +
532                "startCol=" + location.bodyStartCol + ", " +
533                "endCol=" + location.bodyEndCol + "]";
534    }
535
536
537    // ********************************************************************************************
538    // ********************************************************************************************
539    // Abstract-Class ToString
540    // ********************************************************************************************
541    // ********************************************************************************************
542
543
544    /**
545     * Dummy Method.  Overriden by Concrete Sub-Classes.
546     * @see Method#toString()
547     * @see Field#toString()
548     * @see Constructor#toString()
549     */
550    public String toString()
551    { return "Declaration is Abstract, all Concrete Sub-Classes Override this method."; }
552
553    /**
554     * Dummy Method.  Overriden by Concrete Sub-Classes.
555     * @see Method#toString(int)
556     * @see Field#toString(int)
557     * @see Constructor#toString(int)
558     */
559    public String toString(int flags)
560    { return "Declaration is Abstract, all Concrete Sub-Classes Override this method."; }
561}