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