001package Torello.JavaDoc;
002
003
004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
005// Java-HTML Imports
006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
007
008import Torello.Java.*;
009
010import static Torello.Java.C.*;
011import static Torello.JavaDoc.PF.*;
012
013
014// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
015// Standard-Java Imports
016// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
017
018import java.util.Optional;
019import java.io.IOException;
020
021
022// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
023// The new Source-Code Parser: com.sun.source.*
024// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
025
026import com.sun.source.tree.Tree;
027import com.sun.source.doctree.DocCommentTree;
028
029/**
030 * Location Information storing line-number, column-number and character-number for items inside
031 * of a Java Source-Code File (a {@code '.java'} file).
032 */
033public class Location implements java.io.Serializable, Cloneable
034{
035    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
036    protected static final long serialVersionUID = 1;
037
038
039    // ********************************************************************************************
040    // ********************************************************************************************
041    // This class' public fields
042    // ********************************************************************************************
043    // ********************************************************************************************
044
045
046    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_SIG_START_POS> */
047    public final int signatureStartPos;
048
049    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_SIG_START_LINE> */
050    public final int signatureStartLine;
051
052    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_SIG_START_COL> */
053    public final int signatureStartCol;
054
055
056    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_SIG_END_POS> */
057    public final int signatureEndPos;
058
059    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_SIG_END_LINE> */
060    public final int signatureEndLine;
061
062    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_SIG_END_COL> */
063    public final int signatureEndCol;
064
065
066    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_JDC_START_POS> */
067    public final int jdcStartPos;
068
069    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_JDC_START_LINE> */
070    public final int jdcStartLine;
071
072    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_JDC_START_COL> */
073    public final int jdcStartCol;
074
075
076    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_JDC_END_POS> */
077    public final int jdcEndPos;
078
079    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_JDC_END_LINE> */
080    public final int jdcEndLine;
081
082    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_JDC_END_COL> */
083    public final int jdcEndCol;
084
085
086    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_BODY_START_POS> */
087    public final int bodyStartPos;
088
089    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_BODY_START_LINE> */
090    public final int bodyStartLine;
091
092    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_BODY_START_COL> */
093    public final int bodyStartCol;
094
095
096    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_BODY_END_POS> */
097    public final int bodyEndPos;
098
099    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_BODY_END_LINE> */
100    public final int bodyEndLine;
101
102    /** <EMBED CLASS='external-html' DATA-FILE-ID=LOC_BODY_END_COL> */
103    public final int bodyEndCol;
104
105
106    // ********************************************************************************************
107    // ********************************************************************************************
108    // Constructor - com.sun.source.tree 
109    // ********************************************************************************************
110    // ********************************************************************************************
111
112
113    Location(TreeUtils util, Tree tree, DocCommentTree dct, Tree body, Tree fieldInitializerTree)
114    {
115        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
116        // Java-Doc Comments Location-Information
117        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
118
119        if (dct == null)
120        {
121            // If this 'entity' doesn't have a JavaDoc Comment, then set these to '-1'
122            this.jdcStartPos    = this.jdcEndPos    = -1;
123            this.jdcStartLine   = this.jdcEndLine   = -1;
124            this.jdcStartCol    = this.jdcEndCol    = -1;
125        }
126
127        else
128        {
129            int sPos = (int) util.docSourcePositions.getStartPosition
130                (util.compilationUnitTree, dct, dct);
131
132            int ePos = (int) util.docSourcePositions.getEndPosition
133                (util.compilationUnitTree, dct, dct);
134
135            // This can happen if the code has a /**  */ above a field or method that turns out to
136            // just be totally and completely empty!  I am a little busy at the moment documenting
137            // something else.  March 5th, 2024.  This is trivial, but I am not doing right now.
138
139            if (ePos == -1) throw new Torello.Java.ToDoException(
140                "This really needs to be analyzed, and it is likely very easy, but I am in the " +
141                "middle of another documentation-thing right now...\n\n" +
142                "To Quickly Fix your problem, make sure there are no JavaDoc Comments that look " +
143                "like /** */ - where there is nothing but white-space inside your comment.\n\n" +
144                "I will get to this hopefully soon.  Today is March 4th, 2024."
145            );
146
147            while (sPos >= 2)
148                if (util.srcFileAsStr.charAt(sPos--) == '*')
149                    if (util.srcFileAsStr.regionMatches(sPos - 1, "/**", 0, 3))
150                    { sPos--; break; }
151
152            int MAX = util.srcFileAsStr.length() - 2;
153
154            while (ePos < MAX)
155                if (util.srcFileAsStr.charAt(ePos++) == '*')
156                    if (util.srcFileAsStr.regionMatches(ePos - 1, "*/", 0, 2))
157                    { ePos++; break; }
158
159            this.jdcStartPos    = sPos;
160            this.jdcEndPos      = ePos;
161
162            this.jdcStartLine   = (int) util.lineMap.getLineNumber(sPos);
163            this.jdcEndLine     = (int) util.lineMap.getLineNumber(ePos);
164
165            this.jdcStartCol    = positionToColumn(this.jdcStartPos, util.srcFileAsStr);
166            this.jdcEndCol      = positionToColumn(this.jdcEndPos, util.srcFileAsStr);
167
168            /*
169            System.out.println(
170                "TU: " + StrPrint.abbrev(
171                    util.srcFileAsStr.substring(this.jdcStartPos, this.jdcEndPos),
172                    60, true, null, 120
173                ));
174            */
175        }
176
177
178        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
179        // Body Location-Information
180        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
181        //
182        // NOTE: Fields that do not have any initialization expressions, and absolutely enum
183        //       constants - will not have a body, and the 'body' parameter will be null in such
184        //       cases.  Annotation-Elements without a default-value may pass null to the body too,
185        //       as could a method defined inside of an interface that doesn't have a definition.
186
187        if (body == null)
188        {
189            // If this 'entity' doesn't have a Body, then set these to '-1'
190            this.bodyStartPos   = this.bodyEndPos   = -1;
191            this.bodyStartLine  = this.bodyEndLine  = -1;
192            this.bodyStartCol   = this.bodyEndCol   = -1;
193        }
194        else
195        {
196            this.bodyStartPos = (int) util.sourcePositions.getStartPosition
197                (util.compilationUnitTree, body);
198
199            this.bodyEndPos = (int) util.sourcePositions.getEndPosition
200                (util.compilationUnitTree, body);
201
202            this.bodyStartLine  = (int) util.lineMap.getLineNumber(this.bodyStartPos);
203            this.bodyEndLine    = (int) util.lineMap.getLineNumber(this.bodyEndPos);
204
205            this.bodyStartCol   = positionToColumn(this.bodyStartPos, util.srcFileAsStr);
206            this.bodyEndCol     = positionToColumn(this.bodyEndPos, util.srcFileAsStr);
207
208            /*
209            System.out.println(
210                "TU: " + StrPrint.abbrev(
211                    util.srcFileAsStr.substring(this.bodyStartPos, this.bodyEndPos),
212                    60, true, null, 120
213                ));
214            */
215        }
216
217
218        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
219        // Signature Location-Information
220        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
221
222        this.signatureStartPos = (int) util.sourcePositions.getStartPosition
223            (util.compilationUnitTree, tree);
224
225        this.signatureStartLine = (int) util.lineMap.getLineNumber(this.signatureStartPos);
226        this.signatureStartCol  = positionToColumn(this.signatureStartPos, util.srcFileAsStr);
227
228        if (fieldInitializerTree != null)
229        {
230            // NOTE: Here, a '+1' is added at the very end of the statement to account for the
231            //       ending semi-colon, which Java-Parser is adding.
232
233            this.signatureEndPos = (int) util.sourcePositions.getEndPosition
234                (util.compilationUnitTree, fieldInitializerTree) + 1;
235
236            this.signatureEndLine   = (int) util.lineMap.getLineNumber(this.signatureEndPos);
237            this.signatureEndCol    = positionToColumn(this.signatureEndPos, util.srcFileAsStr);
238        }
239        else if (body == null)
240        {
241            this.signatureEndPos = (int) util.sourcePositions.getEndPosition
242                (util.compilationUnitTree, tree);
243
244            this.signatureEndLine   = (int) util.lineMap.getLineNumber(this.signatureEndPos);
245            this.signatureEndCol    = positionToColumn(this.signatureEndPos, util.srcFileAsStr);
246        }
247        else
248        {
249            int     line    = this.bodyStartLine;
250            int     pos     = this.bodyStartPos;
251            int     col     = 2;
252            char    c       = 0;
253
254            while (Character.isWhitespace(c = util.srcFileAsStr.charAt(--pos))) if (c == '\n') line--;
255            while (util.srcFileAsStr.charAt(--pos) != '\n') col++;
256
257            this.signatureEndLine   = line;
258            this.signatureEndCol    = col;
259            this.signatureEndPos    = pos + col;
260        }
261    }
262
263
264    // ********************************************************************************************
265    // ********************************************************************************************
266    // Constructor for NestedType - com.sun.source.tree
267    // ********************************************************************************************
268    // ********************************************************************************************
269
270
271    Location(TreeUtils util, Tree tree, DocCommentTree dct)
272    {
273        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
274        // Java-Doc Comments Location (COPIED DIRECTLY/VERBATIM FROM PREVIOUS CONSTRUCTOR)
275        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
276
277        if (dct == null)
278        {
279            // If this 'entity' doesn't have a JavaDoc Comment, then set these to '-1'
280            this.jdcStartPos    = this.jdcEndPos    = -1;
281            this.jdcStartLine   = this.jdcEndLine   = -1;
282            this.jdcStartCol    = this.jdcEndCol    = -1;
283        }
284        else
285        {
286            int sPos = (int) util.docSourcePositions.getStartPosition
287                (util.compilationUnitTree, dct, dct);
288
289            int ePos = (int) util.docSourcePositions.getEndPosition
290                (util.compilationUnitTree, dct, dct);
291
292            while (sPos >= 2)
293                if (util.srcFileAsStr.charAt(sPos--) == '*')
294                    if (util.srcFileAsStr.regionMatches(sPos - 1, "/**", 0, 3))
295                    { sPos--; break; }
296
297            int MAX = util.srcFileAsStr.length() - 2;
298            while (ePos < MAX)
299                if (util.srcFileAsStr.charAt(ePos++) == '*')
300                    if (util.srcFileAsStr.regionMatches(ePos - 1, "*/", 0, 2))
301                    { ePos++; break; }
302
303            this.jdcStartPos    = sPos;
304            this.jdcEndPos      = ePos;
305
306            this.jdcStartLine   = (int) util.lineMap.getLineNumber(sPos);
307            this.jdcEndLine     = (int) util.lineMap.getLineNumber(ePos);
308
309            this.jdcStartCol    = positionToColumn(this.jdcStartPos, util.srcFileAsStr);
310            this.jdcEndCol      = positionToColumn(this.jdcEndPos, util.srcFileAsStr);
311        }
312
313
314        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
315        // Signature Location-Information - ONLY DO THE STARTING PART
316        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
317
318        this.signatureStartPos = (int) util.sourcePositions.getStartPosition
319            (util.compilationUnitTree, tree);
320
321        this.signatureStartLine = (int) util.lineMap.getLineNumber(this.signatureStartPos);
322        this.signatureStartCol  = positionToColumn(this.signatureStartPos, util.srcFileAsStr);
323
324
325        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
326        // Now do the body ***AND*** The rest of signature
327        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
328
329        int     line    = this.signatureStartLine;
330        int     col     = this.signatureStartCol;
331        int     pos     = StrIndexOf.nth(util.srcFileAsStr, line - 1, '\n') + col;
332        int     MAX     = util.srcFileAsStr.length() - 1;
333        char    c       = 0;
334
335        while ((pos < MAX) && ((c = util.srcFileAsStr.charAt(++pos)) != '{') && (c != ';'))
336            if (c == '\n') line++;
337
338        if (c == '{')
339        {
340            this.bodyStartPos   = pos;
341            this.bodyStartLine  = line;
342            this.bodyStartCol   = positionToColumn(pos, util.srcFileAsStr);
343
344            this.bodyEndPos = (int) util.sourcePositions.getEndPosition
345                (util.compilationUnitTree, tree);
346
347            this.bodyEndLine    = (int) util.lineMap.getLineNumber(this.bodyEndPos);
348            this.bodyEndCol     = positionToColumn(this.bodyEndPos, util.srcFileAsStr);
349
350
351            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
352            // Signature-End
353            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
354
355            while ((--pos > 0) && Character.isWhitespace(c = util.srcFileAsStr.charAt(pos)))
356                if (c == '\n') line--;
357
358            this.signatureEndLine   = line;
359            this.signatureEndPos    = pos + 1;
360            this.signatureEndCol    = positionToColumn(this.signatureEndPos , util.srcFileAsStr);
361        }
362        else
363        {
364            this.bodyStartPos = this.bodyStartCol = this.bodyStartLine =
365            this.bodyEndPos = this.bodyEndCol = this.bodyEndLine = -1;
366
367
368            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
369            // Signature-End
370            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
371
372            this.signatureEndPos = (int) util.sourcePositions.getEndPosition
373                (util.compilationUnitTree, tree);
374
375            this.signatureEndLine    = (int) util.lineMap.getLineNumber(this.signatureEndPos);
376            this.signatureEndCol     = positionToColumn(this.signatureEndPos, util.srcFileAsStr);
377        }
378    }
379
380
381    // ********************************************************************************************
382    // ********************************************************************************************
383    // Two Simple Constructor Helpers
384    // ********************************************************************************************
385    // ********************************************************************************************
386
387
388    private static int positionToColumn(int pos, String srcFileAsStr)
389    {
390        int     col = 1;
391        char    c;
392
393        while (     (--pos >= 0)
394                &&  ((c = srcFileAsStr.charAt(pos)) != '\n')
395                &&  (c != '\r')
396        )
397            col++;
398
399        return col;
400    }
401
402    // It is expected the line1, col1, pos1 define a specific location / are "consisten"
403    // (I Hope you know what I mean by "consistent")
404    //
405    // ALSO: line2 & col2 are also consistent, and come AFTER the first position
406    private static int colAndLineToPosition
407        (String srcFileAsStr, int line1, int col1, int pos1, int line2, int col2)
408    {
409        if (line2 > line1)
410        {
411            // The presumption, here, is that 'pos1' is a "starting" location - for either the body
412            // or the signature.  It **WILL NOT** be a new-line '\n' character, it will be
413            // something like the letter 'p' which is the first letter in 'public' or 'private'
414            //
415            // If this is for a body, then it will hold a '{'  The only reason this code uses 'pos'
416            // rather than just re-using 'pos1' from the input-parameter / signature, is for this
417            // comment that you are reading right now!
418
419            int pos = pos1;
420            for (int count = line2-line1; count > 0; )
421                if (srcFileAsStr.charAt(++pos) == '\n') count--;
422
423            return pos + col2;
424        }
425        else if (line2 == line1) 
426            return pos1 - col1 + col2;
427
428        // This should never happen
429        else
430            throw new UnreachableError();
431    }
432
433    // ********************************************************************************************
434    // ********************************************************************************************
435    // Private Clone Constructor
436    // ********************************************************************************************
437    // ********************************************************************************************
438
439
440    private Location(Location l)
441    {
442        this.signatureStartPos  = l.signatureStartPos;
443        this.signatureStartLine = l.signatureStartLine;
444        this.signatureStartCol  = l.signatureStartCol;
445    
446        this.signatureEndPos    = l.signatureEndPos;
447        this.signatureEndLine   = l.signatureEndLine;
448        this.signatureEndCol    = l.signatureEndCol;
449    
450        this.jdcStartPos        = l.jdcStartPos;
451        this.jdcStartLine       = l.jdcStartLine;
452        this.jdcStartCol        = l.jdcStartCol;
453    
454        this.jdcEndPos          = l.jdcEndPos;
455        this.jdcEndLine         = l.jdcEndLine;
456        this.jdcEndCol          = l.jdcEndCol;
457    
458        this.bodyStartPos       = l.bodyStartPos;
459        this.bodyStartLine      = l.bodyStartLine;
460        this.bodyStartCol       = l.bodyStartCol;
461    
462        this.bodyEndPos         = l.bodyEndPos;
463        this.bodyEndLine        = l.bodyEndLine;
464        this.bodyEndCol         = l.bodyEndCol;
465    }
466
467
468    // ********************************************************************************************
469    // ********************************************************************************************
470    // java.lang.Object methods
471    // ********************************************************************************************
472    // ********************************************************************************************
473
474
475    /**
476     * Standard Java {@code toString()} method
477     * @return Returns the contents of this class, as a {@code java.lang.String}
478     */
479    public String toString()
480    {
481        return
482            "signatureStartPos:  " + signatureStartPos + '\n' +
483            "signatureStartLine: " + signatureStartLine + '\n' +
484            "signatureStartCol:  " + signatureStartCol + '\n' +
485    
486            "signatureEndPos:    " + signatureEndPos + '\n' +
487            "signatureEndLine:   " + signatureEndLine + '\n' +
488            "signatureEndCol:    " + signatureEndCol + '\n' +
489    
490            "jdcStartPos:        " + jdcStartPos + '\n' +
491            "jdcStartLine:       " + jdcStartLine + '\n' +
492            "jdcStartCol:        " + jdcStartCol + '\n' +
493    
494            "jdcEndPos:          " + jdcEndPos + '\n' +
495            "jdcEndLine:         " + jdcEndLine + '\n' +
496            "jdcEndCol:          " + jdcEndCol + '\n' +
497    
498            "bodyStartPos:       " + bodyStartPos + '\n' +
499            "bodyStartLine:      " + bodyStartLine + '\n' +
500            "bodyStartCol:       " + bodyStartCol + '\n' +
501    
502            "bodyEndPos:         " + bodyEndPos + '\n' +
503            "bodyEndLine:        " + bodyEndLine + '\n' +
504            "bodyEndCol:         " + bodyEndCol + '\n';
505    }
506
507    /**
508     * Standard Java {@code clone()} method
509     * @return Returns a copy of {@code 'this'} instance
510     */
511    public Object clone()
512    { return new Location(this); }
513
514    /**
515     * Standard Java {@code equals()} method
516     * 
517     * @param other This may be any Java Object, but one that extends class {@code 'Location'}
518     * has the potential to result in a {@code TRUE} evaluation from this method.
519     * 
520     * @return {@code TRUE} if and only if the contents of {@code 'this'} instance are identical to
521     * the contents of {@code 'other'} (and only if {@code 'other'} is actually an instance of
522     * {@code Location}, or extends at least extends it).
523     */
524    public boolean equals(Object other)
525    {
526        if (! Location.class.isAssignableFrom(other.getClass())) return false;
527
528        Location l = (Location) other;
529
530        return
531                (this.signatureStartPos     == l.signatureStartPos)
532            &&  (this.signatureStartLine    == l.signatureStartLine)
533            &&  (this.signatureStartCol     == l.signatureStartCol)
534    
535            &&  (this.signatureEndPos       == l.signatureEndPos)
536            &&  (this.signatureEndLine      == l.signatureEndLine)
537            &&  (this.signatureEndCol       == l.signatureEndCol)
538    
539            &&  (this.jdcStartPos           == l.jdcStartPos)
540            &&  (this.jdcStartLine          == l.jdcStartLine)
541            &&  (this.jdcStartCol           == l.jdcStartCol)
542    
543            &&  (this.jdcEndPos             == l.jdcEndPos)
544            &&  (this.jdcEndLine            == l.jdcEndLine)
545            &&  (this.jdcEndCol             == l.jdcEndCol)
546    
547            &&  (this.bodyStartPos          == l.bodyStartPos)
548            &&  (this.bodyStartLine         == l.bodyStartLine)
549            &&  (this.bodyStartCol          == l.bodyStartCol)
550    
551            &&  (this.bodyEndPos            == l.bodyEndPos)
552            &&  (this.bodyEndLine           == l.bodyEndLine)
553            &&  (this.bodyEndCol            == l.bodyEndCol);
554    }
555
556    /**
557     * Simply invokes the {@code hashCode()} static-method provided by class {@code java.lang.Integer}.
558     * @return a hash code value for this object.
559     */
560    public int hashCode()
561    { return Integer.hashCode(this.signatureStartPos * this.signatureEndPos); }
562
563
564    // ********************************************************************************************
565    // ********************************************************************************************
566    // Specialized toString
567    // ********************************************************************************************
568    // ********************************************************************************************
569
570
571    /**
572     * Generates a {@code String} - with all information available, including any content requested
573     * by the {@code 'flags'} parameter.
574     * 
575     * @param flags These are the {@code toString(...)} flags from class {@code PF}
576     * ("Print Flags"). View available flags listed in class {@link PF}.
577     * 
578     * @param srcFileAsStr This parameter should contain the complete {@code '.java'} source-code
579     * file as a {@code String}.  If you have passed the Print-Flags for requesting that the body
580     * or Java-Doc Comment be output to the returned-{@code String}, this parameter must be passed
581     * a valid copy of the {@code '.java'} File.
582     * 
583     * <BR /><BR />This parameter may be null, and if it is it will be ignored.  When null is
584     * passed to this parameter, the actual Body, Java-Doc Comment &amp; Signature simply cannot
585     * be extracted, and the output of this {@code toString} method shall only print the location
586     * numbers, column's and line-numbers instead.
587     * 
588     * <BR /><BR />If a valid copy of the contents of the {@code '.java'} file that produced
589     * {@code 'this'} instance of {@code Location} is passed <B STYLE='color: red;'><I>and</I></B>
590     * if the appropriate Print-Flags are passed tot he {@code 'flags'} parameter requesting that
591     * the specified-elements (signature, comment and body) be output to the
592     * returned-{@code String},  <B STYLE='color: red;'><I>then</I></B> those elements will be 
593     * printed to the output-{@code String}.
594     * 
595     * <BR /><BR /><B>NOTE:</B> If the contents of parameter {@code 'srcFileAsstr'} are not the
596     * exact and un-modified contents of the {@code'.java} file that produced {@code 'this'}
597     * instance of location, then the {@code String} returned will contain erroneous information.
598     * It is even possible that a {@code StringIndexOutOfBoundsException} may be thrown.
599     * 
600     * @return A printable {@code String} of the locations represented by this instance
601     * 
602     * @see PF
603     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
604     * @see #toString()
605     */
606    public String toString(int flags, String srcFileAsStr)
607    {
608        boolean color       = (flags & UNIX_COLORS) > 0;
609        boolean src         = srcFileAsStr != null;
610        boolean signature   = src;
611        boolean bodyShort   = src && ((flags & BODY_SHORT) > 0);
612        boolean bodyLong    = (! bodyShort) && src && ((flags & BODY) > 0);
613        boolean jdc         = src && ((flags & JAVADOC_COMMENTS) > 0);
614        boolean locShort    = (flags & BRIEF_LOCATION) > 0;
615        int     M_OVER_2    = MAX_STR_LEN / 2;
616
617        if (locShort) return
618
619            (signature
620                ? ("Signature:        " + StrIndent.indentAfter2ndLine
621                    (srcFileAsStr.substring(signatureStartPos, signatureEndPos), 4, true, false) +
622                    '\n')
623                : "") +
624
625            "Signature-Start:  " +
626            "pos="  + (color ? BGREEN : "") + signatureStartPos  + (color ? RESET : "") + ", " +
627            "line=" + (color ? BGREEN : "") + signatureStartLine + (color ? RESET : "") + ", " +
628            "col="  + (color ? BGREEN : "") + signatureStartCol  + (color ? RESET : "") + "\n" +
629
630            "Signature-End:    " +
631            "pos="  + (color ? BCYAN : "") + signatureEndPos  + (color ? RESET : "") + ", " +
632            "line=" + (color ? BCYAN : "") + signatureEndLine + (color ? RESET : "") + ", " +
633            "col="  + (color ? BCYAN : "") + signatureEndCol  + (color ? RESET : "") + "\n" +
634
635            (jdc
636                ? ("Java-Doc Comment: " + StrPrint.abbrev(srcFileAsStr.substring
637                    (jdcStartPos, jdcEndPos), M_OVER_2, true, null, MAX_STR_LEN) + '\n')
638                : "") +
639
640            "Java-Doc-Start:   " +
641            "pos="  + (color ? BGREEN : "") + jdcStartPos  + (color ? RESET : "") + ", " +
642            "line=" + (color ? BGREEN : "") + jdcStartLine + (color ? RESET : "") + ", " +
643            "col="  + (color ? BGREEN : "") + jdcStartCol  + (color ? RESET : "") + "\n" +
644
645            "Java-Doc-End:     " +
646            "pos="  + (color ? BCYAN : "") + jdcEndPos  + (color ? RESET : "") + ", " +
647            "line=" + (color ? BCYAN : "") + jdcEndLine + (color ? RESET : "") + ", " +
648            "col="  + (color ? BCYAN : "") + jdcEndCol  + (color ? RESET : "") + "\n" +
649
650            (bodyShort
651                ? ("Body:             " + StrPrint.abbrev(srcFileAsStr.substring
652                    (signatureStartPos, signatureEndPos), M_OVER_2, true, null, MAX_STR_LEN))
653                : "") +
654
655            (bodyLong
656                ? ("Body:             " + StrIndent.indentAfter2ndLine
657                    (srcFileAsStr.substring(signatureStartPos, signatureEndPos), 4, true, false))
658                : "") +
659
660            "Body-Start:       " +
661            "pos="  + (color ? BGREEN : "") + bodyStartPos  + (color ? RESET : "") + ", " +
662            "line=" + (color ? BGREEN : "") + bodyStartLine + (color ? RESET : "") + ", " +
663            "col="  + (color ? BGREEN : "") + bodyStartCol  + (color ? RESET : "") + "\n" +
664
665            "Body-End:         " +
666            "pos="  + (color ? BCYAN : "") + bodyEndPos  + (color ? RESET : "") + ", " +
667            "line=" + (color ? BCYAN : "") + bodyEndLine + (color ? RESET : "") + ", " +
668            "col="  + (color ? BCYAN : "") + bodyEndCol  + (color ? RESET : "");
669
670        else return
671
672            (signature
673                ? ("SIGNATURE: " + StrIndent.indentAfter2ndLine
674                    (srcFileAsStr.substring(signatureStartPos, signatureEndPos), 4, true, false))
675                : "") +
676
677            "signatureStartPos:  " + (color ? BGREEN : "") + signatureStartPos + '\n' +
678                (color ? RESET : "") + 
679            "signatureStartLine: " + (color ? BGREEN : "") + signatureStartLine + '\n' +
680                (color ? RESET : "") + 
681            "signatureStartCol:  " + (color ? BGREEN : "") + signatureStartCol + '\n' +
682                (color ? RESET : "") + 
683    
684            "signatureEndPos:    " + (color ? BCYAN : "") + signatureEndPos + '\n' +
685                (color ? RESET : "") + 
686            "signatureEndLine:   " + (color ? BCYAN : "") + signatureEndLine + '\n' +
687                (color ? RESET : "") + 
688            "signatureEndCol:    " + (color ? BCYAN : "") + signatureEndCol + '\n' +
689                (color ? RESET : "") + 
690
691            (jdc
692                ? ("BODY: " + StrPrint.abbrev(srcFileAsStr.substring
693                    (jdcStartPos, jdcEndPos), M_OVER_2, true, null, MAX_STR_LEN))
694                : "") +
695
696            "jdcStartPos:        " + (color ? BGREEN : "") + jdcStartPos + '\n' +
697                (color ? RESET : "") + 
698            "jdcStartLine:       " + (color ? BGREEN : "") + jdcStartLine + '\n' +
699                (color ? RESET : "") + 
700            "jdcStartCol:        " + (color ? BGREEN : "") + jdcStartCol + '\n' +
701                (color ? RESET : "") + 
702
703            "jdcEndPos:          " + (color ? BCYAN : "") + jdcEndPos + '\n' +
704                (color ? RESET : "") + 
705            "jdcEndLine:         " + (color ? BCYAN : "") + jdcEndLine + '\n' +
706                (color ? RESET : "") + 
707            "jdcEndCol:          " + (color ? BCYAN : "") + jdcEndCol + '\n' +
708                (color ? RESET : "") + 
709
710            (bodyShort
711                ? ("BODY: " + StrPrint.abbrev(srcFileAsStr.substring
712                    (signatureStartPos, signatureEndPos), M_OVER_2, true, null, MAX_STR_LEN))
713                : "") +
714
715            (bodyLong
716                ? ("BODY: " + StrIndent.indentAfter2ndLine
717                    (srcFileAsStr.substring(signatureStartPos, signatureEndPos), 4, true, false))
718                : "") +
719
720            "bodyStartPos:       " + (color ? BGREEN : "") + bodyStartPos +'\n' +
721                (color ? RESET : "") + 
722            "bodyStartLine:      " + (color ? BGREEN : "") + bodyStartLine + '\n' +
723                (color ? RESET : "") +
724            "bodyStartCol:       " + (color ? BGREEN : "") + bodyStartCol + '\n' +
725                (color ? RESET : "") + 
726
727            "bodyEndPos:         " + (color ? BCYAN : "") + bodyEndPos + '\n' +
728                (color ? RESET : "") + 
729            "bodyEndLine:        " + (color ? BCYAN : "") + bodyEndLine + '\n' +
730                (color ? RESET : "") + 
731            "bodyEndCol:         " + (color ? BCYAN : "") + bodyEndCol + '\n' +
732                (color ? RESET : "");
733    }
734
735    /**
736     * Produces a quick-summary, as a {@code String}.
737     * @return a very brief summary of the information contained by this class.  Lists only the
738     * starting line numbers for the three sections.
739     */
740    public String quickSummary()
741    {
742        return "signature-line=" + this.signatureStartLine + ", javadoc-line=" + this.jdcStartLine +
743            ", body-line=" + this.bodyStartLine;        
744    }
745
746
747    // ********************************************************************************************
748    // ********************************************************************************************
749    // Error-Checking
750    // ********************************************************************************************
751    // ********************************************************************************************
752
753
754    private void check()
755    {
756
757    }
758
759
760    // ********************************************************************************************
761    // ********************************************************************************************
762    // Package-Private Debugging Tool for finding where two Declaration instances are different
763    // ********************************************************************************************
764    // ********************************************************************************************
765
766
767    // NOTE: This class has a local copy of 'diff' -> since the only diff's that are being done
768    //       here are for integers.
769
770    void diff(Location other, Appendable a, String indentation) throws IOException
771    {
772        diff(this.signatureStartPos, other.signatureStartPos, "signatureStartPos", a, indentation);
773
774        diff(
775            this.signatureStartLine, other.signatureStartLine, "signatureStartLine", a,
776            indentation
777        );
778
779        diff(this.signatureStartCol, other.signatureStartCol, "signatureStartCol", a, indentation);
780
781        diff(this.signatureEndPos, other.signatureEndPos, "signatureEndPos", a, indentation);
782        diff(this.signatureEndLine, other.signatureEndLine, "signatureEndLine", a, indentation);
783        diff(this.signatureEndCol, other.signatureEndCol, "signatureEndCol", a, indentation);
784
785        diff(this.jdcStartPos, other.jdcStartPos, "jdcStartPos", a, indentation);
786        diff(this.jdcStartLine, other.jdcStartLine, "jdcStartLine", a, indentation);
787        diff(this.jdcStartCol, other.jdcStartCol, "jdcStartCol", a, indentation);
788
789        diff(this.jdcEndPos, other.jdcEndPos, "jdcEndPos", a, indentation);
790        diff(this.jdcEndLine, other.jdcEndLine, "jdcEndLine", a, indentation);
791        diff(this.jdcEndCol, other.jdcEndCol, "jdcEndCol", a, indentation);
792
793        diff(this.bodyStartPos, other.bodyStartPos, "bodyStartPos", a, indentation);
794        diff(this.bodyStartLine, other.bodyStartLine, "bodyStartLine", a, indentation);
795        diff(this.bodyStartCol, other.bodyStartCol, "bodyStartCol", a, indentation);
796
797        diff(this.bodyEndPos, other.bodyEndPos, "bodyEndPos", a, indentation);
798        diff(this.bodyEndLine, other.bodyEndLine, "bodyEndLine", a, indentation);
799        diff(this.bodyEndCol, other.bodyEndCol, "bodyEndCol", a, indentation);
800    }
801
802    private void diff(int int1, int int2, String intName, Appendable a, String indentation)
803        throws IOException
804    {
805        if (int2 != int1) a.append(
806            indentation +
807            "this.location." + intName + ": [" + BGREEN + ("" + int1) + RESET + "], " +
808            "other.location." + intName + ": [" + BGREEN + ("" + int2) + RESET + "]\n"
809        );
810    }
811}