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