001package Torello.JavaDoc;
002
003
004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
005// Standard-Java Imports
006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
007
008import java.io.IOException;
009import java.util.Optional;
010
011
012// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
013// Java-HTML Imports
014// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
015
016import Torello.Java.*;
017
018import static Torello.Java.C.*;
019import static Torello.JavaDoc.PF.*;
020
021import Torello.Java.Additional.Ret2;
022
023import Torello.JDUInternal.DataClasses.MainLoopData.CallableSignature;
024
025
026// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
027// The new Source-Code Parser: com.sun.source.*
028// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
029
030import com.sun.source.tree.MethodTree;
031
032
033/**
034 * <B STYLE='color:darkred;'>Reflection Class:</B>
035 * 
036 * Holds all information extracted from <CODE>'&#46;java'</CODE> Source-Files about Method's
037 * identified in that file.
038 * 
039 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_GET_INST>
040 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_METHOD>
041 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DIAGRAM>
042 */
043@JDHeaderBackgroundImg(EmbedTagFileID={"REFLECTION_EXTENSION"})
044public class Method
045    extends Callable
046    implements java.io.Serializable, Comparable<Method>, Cloneable
047{
048    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
049    public static final long serialVersionUID = 1;
050
051    /**
052     * The return type of the {@code method}, as a {@code String}.  If this is a method with a
053     * {@code 'void'} return-type, this shall be "void".
054     * 
055     * <BR /><BR /><B>NOTE:</B> The parsed return-type will include the full-package name of the
056     * returned class (or interface), if the {@code method} returns a class or interface. 
057     */
058    public final String returnType;
059
060    /**
061     * The return type of the {@code method}, as a {@code String}.<BR /><BR />
062     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JOW_TITLE>
063     */
064    public final String returnTypeJOW;
065
066
067    // ********************************************************************************************
068    // ********************************************************************************************
069    // Reference-Hook: com.sun.source.tree
070    // ********************************************************************************************
071    // ********************************************************************************************
072
073
074    /**
075     * <EMBED CLASS='external-html' DATA-FILE-ID=SSTB_HOOK_FIELD>
076     * 
077     * If a user decides to make use of the native Sun/Oracle {@code MethodTree} instance that was
078     * used to build this {@code Method} instance, it may be retrieved from this {@code transient}
079     * field.
080     */
081    public final transient MethodTree methodTree;
082
083
084    // ********************************************************************************************
085    // ********************************************************************************************
086    // Constructor - com.sun.source.tree 
087    // ********************************************************************************************
088    // ********************************************************************************************
089
090    
091    /**
092     * <EMBED CLASS="defs" DATA-KIND=Method DATA-ENTITY=MethodTree>
093     * <EMBED CLASS='external-html' DATA-FILE-ID=RC_DESCRIPTION>
094     * @param mt <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_TREE>
095     * @param util <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_UTIL>
096     */
097    public Method(MethodTree mt, TreeUtils util)
098    {
099        super(mt, mt.getName().toString(), Entity.METHOD, util);
100
101        this.returnType     = mt.getReturnType().toString();
102        this.returnTypeJOW  = StrSource.typeToJavaIdentifier(this.returnType);
103        this.methodTree     = mt;
104    }
105
106
107    // ********************************************************************************************
108    // ********************************************************************************************
109    // Constructor: Used Internally by SignatureParse / SummaryHTMLFile
110    // ********************************************************************************************
111    // ********************************************************************************************
112
113
114    // Ensures that the Version with longer type-information strings is used.
115    // Java Doc often uses longer type strings than is available from the source-code parse
116    // Remember, JavaParser Symbol-Solver doesn't work well, and the Sun/Oracle Parser doesn't have
117    // a linker at all.
118    //
119    // Called from JDUInternal.ParseHTML.SignatureParse:
120    //      This is used when the JavaDocHTMLFile is asking that a method be retrieved based on
121    //      input from **BOTH** the HTML-File **AND** the Source-File
122
123    public Method(CallableSignature cSig, Method mFromSourceParser)
124    {
125        // Does the same thing as the loop statement below, but for the "parameterTypes"
126        super(cSig, mFromSourceParser);
127
128        // Java Doc always produces "java.lang.String", while JP just gives "String"
129        //
130        // REMEMBER: JP is lazy when it comes to "Package Information" for types.
131        //           Java-Doc includes it often - BUT NOT ALWAYS.  (See above comment)
132        //
133        // Remember, though, the rest of the JavaParser fields are filled out, Java Doc
134        // leaves out all the other information that JP retrieves.
135
136        this.returnType =
137            (cSig.returnType.length() > mFromSourceParser.returnType.length())
138                ? cSig.returnType
139                : mFromSourceParser.returnType;
140
141        // This should never matter.  They must be identical.
142        this.returnTypeJOW = mFromSourceParser.returnTypeJOW;
143
144        // Save the reference hook
145        this.methodTree = mFromSourceParser.methodTree;
146    }
147
148    // Used for "Synthetic Methods ONLY!"  Literally, this line is the only way this particular
149    // Constructor could ever be called:
150    //
151    // From JDUInternal.ParseHTML.SignatureParse:
152    //      if (StrCmpr.equalsXOR(cSig.name, "valueOf", "values")) return new Method(cSig);
153
154    public Method(CallableSignature cSig)
155    {
156        // Does the same thing as the loop statement below, but for the "parameterTypes"
157        super(cSig, Entity.METHOD);
158
159        this.returnType         = cSig.returnType;
160        this.returnTypeJOW      = cSig.returnTypeJOW;
161        this.methodTree         = null;
162    }
163
164
165    // ********************************************************************************************
166    // ********************************************************************************************
167    // toString()
168    // ********************************************************************************************
169    // ********************************************************************************************
170
171
172    /**
173     * Generates a {@code String} of this {@code method}, with most information included.
174     * 
175     * <BR /><BR /><B>NOTE:</B> This will not return every piece of information contained by this
176     * class. For example, both the method body, and any possible JavaDoc Comments are not
177     * included.  For a more enhanced {@code toString()} version, call the one that accepts flags.
178     * 
179     * @return A printable {@code String} of this method.
180     * 
181     * @see PF
182     * @see #toString(int)
183     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
184     */
185    public String toString()
186    {
187        return
188            "Name:            [" + name + "]\n" +
189            "Signature:       [" + StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" +
190            "Modifiers:       [" + StrCSV.toCSV(modifiers, true, true, null) + "]\n" +
191            printedParameterNamesTS() +
192            printedParameterTypesTS() +
193            "Return Type:     [" + returnType + "]\n" +
194            printedExceptionsTS() +
195
196            // This will **NEVER** be null - unless 'this' instance was built from an HTML File,
197            // rather than a source-code file.  Instances like that are only used temporarily, and
198            // are garbage collected instantly.  Do this check anyway (just in case).
199
200            "Location:        " + ((this.location == null)
201                ? "null" 
202                : ('[' + this.location.quickSummary() + ']'));
203    }
204
205    /**
206     * This class expects a flags that has been masked using the constant ({@code public, static,
207     * final int}) fields of class {@link PF}.  Please view this class for more information about
208     * the flags available for modifying the return-value of this {@code toString()} method.
209     * 
210     * @param flags These are the toString flags from class PF ("Print Flags").  View available
211     * flags listed in class {@link PF}.
212     * 
213     * @return A printable {@code String} of this method, with comment information included as well.
214     * 
215     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
216     * @see #toString()
217     * @see PF
218     */
219    public String toString(int flags)
220    {
221        boolean color = (flags & UNIX_COLORS) > 0;
222        Ret2<Boolean, Boolean> jow = jowFlags(flags);
223
224        return 
225            printedName("Method", 20, color) +
226            printedSignature(20, color) +
227            printedModifiers(20) +
228            printedParamNames() + 
229            printedParamTypes(jow) +
230            printedReturnType(jow, color) +
231            printedExceptions() +
232            printedLocation(20, color, (flags & BRIEF_LOCATION) > 0) +
233
234            // The previous method does not add a '\n' end to the end of the returned string
235            // These are both optional, they add a '\n' AT THE BEGINNING if one of them is included
236
237            printedComments(20, color, (flags & JAVADOC_COMMENTS) > 0) +
238            printedCallableBody(flags);
239    }
240
241    private String printedReturnType(Ret2<Boolean, Boolean> jow, boolean color)
242    {
243        String rt = null, rtJOW = null;
244
245        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
246        // Worry about the colors first
247        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
248
249        if (jow.a || jow.b)
250            rtJOW = color ? (BGREEN + returnTypeJOW + RESET) : returnTypeJOW;
251
252        if (! jow.b)
253            rt = color ? (BGREEN + returnType + RESET) : returnType;
254        
255
256        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
257        // Now print the string
258        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
259
260        if (jow.b /*onlyJOW*/) return "Return Simple-Type: [" + rtJOW + "]\n";
261
262        else if (jow.a /*addJOW*/) return
263            "Return Type:        [" + rt + "]\n" +
264            "Return Simple-Type: [" + rtJOW + "]\n";
265
266        else return "Return Type:        [" + rt + "]\n";
267    }
268
269
270    // ********************************************************************************************
271    // ********************************************************************************************
272    // CompareTo & Equals
273    // ********************************************************************************************
274    // ********************************************************************************************
275
276
277    /**
278     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
279     * using the two method's {@code name} field. If the name comparison will not
280     * suffice in making a decision, then the number of parameters, and parameter-types are used
281     * to making the sort-decision.
282     * 
283     * @param m Any other {@code Method} to be compared to {@code 'this' Method}
284     * 
285     * @return An integer that fulfils Java's {@code interface Comparable<Method> public boolean
286     * compareTo(Method m)} method requirements.
287     */
288    public int compareTo(Method m)
289    {
290        // Identical References
291        if (this == m) return 0;
292
293        // Sorting by ignoring case is best - usually for the looks of a list
294        // NOTE: Returning '0' is bad, because a TreeSet will remove duplicate-elements.  This
295        //       means two different meethods with the same name would not "fit" into a treeset.
296
297        int ret = this.name.compareToIgnoreCase(m.name);
298        if (ret != 0) return ret;
299
300        // Try to identify a different without ignoring case.
301        ret = this.name.compareTo(m.name);
302        if (ret != 0) return ret;
303
304        ret = this.numParameters() - m.numParameters();
305        if (ret != 0) return ret;
306
307        for (int i=0; i < this.parameterTypesJOW.size(); i++)
308        {
309            ret = this.parameterTypesJOW.get(i).compareTo(m.parameterTypesJOW.get(i));
310            if (ret != 0) return ret;
311        }
312
313        return 0;
314    }
315
316    /**
317     * This <I>should be called an "atypical version" of </I>the usual {@code equals(Object other)}
318     * method.  This version of equals merely compares the name and parameters-list of the method.
319     * The presumption here is that the definition of a 'method' only has 
320     * meaning - <I>at all</I> - inside the context of a {@code class, interface, } or
321     * {@code enumerated-type} where that method is defined. Since inside any {@code '.java'}
322     * source-code file, there may only be one method with a given name and parameter-list, this
323     * shall return {@code TRUE} whenever the method being compared has the same name and parameter
324     * types as {@code 'this'} does.
325     * 
326     * @param other This may be any other {@code method}.  It is <I><B>strongly suggested</B></I>
327     * that this be a {@code method} defined in the same {@code '.java'} source-code file as
328     * {@code 'this' method}.
329     * 
330     * @return This method returns {@code TRUE} when {@code 'this'} instance of {@code Method} has
331     * <B>both</B> the same {@code public final Sting name} <B>and</B> the same parameter-list as
332     * {@code 'other'}.
333     */
334    public boolean equals(Method other)
335    {
336        // The method's must have the same name!
337        if (! this.name.equals(other.name)) return false;
338
339        // If the number of parameters in the 'other' instance of Method differ from the number
340        // of parameters in 'this' Method, then return FALSE immediately.  It cannot be a match.
341
342        if (this.numParameters() != other.numParameters()) return false;
343
344        // If both of these have zero parameters, and their names have matched, return true
345        // immediately
346
347        if (this.numParameters() == 0) return true;
348
349        // If any of the parameter-names are different, break immediately and return false;
350        for (int i=0; i < this.parameterNames.size(); i++)
351            if (! this.parameterNames.get(i).equals(other.parameterNames.get(i))) return false;
352
353        // If the parameter-types listed by the javadoc '.html' file differ from the parameter
354        // types listed in the original '.java' source-code file, then break immediately.
355        //
356        // NOTE: The "package-information" for the FULL CLASS OR INTERFACE NAME is not always
357        //       available.
358
359        for (int i=0; i < this.parameterTypesJOW.size(); i++)
360            if (! this.parameterTypesJOW.get(i).equals(other.parameterTypesJOW.get(i)))
361                return false;
362
363        // ALL TEST PASSED
364        return true;
365    }
366}