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