001package Torello.JavaDoc; 002 003 004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 005// Standard-Java Imports 006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 007 008import java.util.concurrent.locks.*; 009 010import java.io.IOException; 011import java.util.Optional; 012import java.util.List; 013import java.util.function.Consumer; 014 015 016// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 017// Java-HTML Imports 018// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 019 020import Torello.Java.*; 021 022import static Torello.Java.C.*; 023import static Torello.JavaDoc.PF.*; 024 025import Torello.Java.Additional.Ret2; 026import Torello.Java.Additional.Ret3; 027 028import Torello.Java.ReadOnly.ReadOnlyList; 029import Torello.Java.ReadOnly.ReadOnlyArrayList; 030 031import Torello.JDUInternal.ParseJavaSource.PJSHelper; 032 033 034// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 035// The new Source-Code Parser: com.sun.source.* 036// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 037 038import com.sun.source.tree.ClassTree; 039import com.sun.source.tree.TypeParameterTree; 040import com.sun.source.tree.Tree; 041 042 043/** 044 * <B STYLE='color:darkred;'>Reflection Class:</B> 045 * 046 * Holds all information extracted from <CODE><B>'.java'</CODE></B> Source-Files regarding 047 * Nested-Types (Inner-Classes). 048 * 049 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_GET_INST_2> 050 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_NESTED> 051 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DIAGRAM> 052 */ 053public class NestedType extends Declaration implements Cloneable 054{ 055 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 056 protected static final long serialVersionUID = 1; 057 058 @Override 059 String codeHiLiteString() { return null; } 060 061 062 // ******************************************************************************************** 063 // ******************************************************************************************** 064 // Public Fields 065 // ******************************************************************************************** 066 // ******************************************************************************************** 067 068 069 /** Identifies whether this is a nested/inner Class, Interface, Enum, Annotation etc... */ 070 public final CIET ciet; 071 072 /** 073 * The name of the package in which the enclosing-class of this nested-type is defined. This 074 * field will be null if the package was not found, or left blank as the 'default class'. 075 */ 076 public final String packageName; 077 078 /** 079 * The {@code name}-field ({@link Declaration#name}) of this class uses the lone 080 * Java-Identifier (Just One Word) which identifies this {@code NestedClass} within the scope 081 * of the enclosing class. However, {@code nameWithContainer} is a {@code String} that also 082 * includes any / all enclosing-class names, each followed-by a {@code '.'} 083 * 084 * <BR /><BR /><B STYLE='color: red;'>EXAMPLE:</B> For Java {@code java.util.Map.Entry<K, V>}, 085 * the {@code nameWithContainer} would be {@code "Map.Entry"}. 086 * 087 * <BR /><BR />Generic Type-Parameter information is <B><I>not</I></B> included in this 088 * {@code String}, and neither is the Package-Name. 089 */ 090 public final String nameWithContainer; 091 092 /** 093 * This field is identical to {@link #nameWithContainer}, but also has the Package-Name 094 * prepended to it, if the Package-Name was present in the enclosing class' {@code '.java'} 095 * file. 096 * 097 * <BR /><BR /><B STYLE='color: red;'>EXAMPLE:</B> For Java {@code java.util.Map.Entry<K, V>}, 098 * the {@code fullyQualifiedName} would be {@code "java.util.Map.Entry"}. 099 */ 100 public final String fullyQualifiedName; 101 102 /** The number of fields that are defined in this inner-type */ 103 public final int numFields; 104 105 /** The number of methods defined in this inner-type */ 106 public final int numMethods; 107 108 /** <EMBED CLASS='external-html' DATA-FILE-ID=NT_GTPARAMS> */ 109 public final ReadOnlyList<String> genericTypeParameters; 110 111 /** 112 * <EMBED CLASS='external-html' DATA-FILE-ID=NT_IMPL_TYPES> 113 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JOW_TITLE> 114 */ 115 public final ReadOnlyList<String> implementedTypesJOW; 116 117 /** <EMBED CLASS='external-html' DATA-FILE-ID=NT_EXTEND_TYPES> */ 118 public final ReadOnlyList<String> extendedTypesJOW; 119 120 121 // ******************************************************************************************** 122 // ******************************************************************************************** 123 // Native Parser Library Hook 124 // ******************************************************************************************** 125 // ******************************************************************************************** 126 127 128 /** 129 * <EMBED CLASS='external-html' DATA-FILE-ID=SSTB_HOOK_FIELD> 130 * 131 * If a user decides to make use of the native Sun/Oracle {@code ClassTree} instance that was 132 * used to build this {@code NestedType} instance, it may be retrieved from this 133 * {@code transient} field. 134 */ 135 public final transient ClassTree classTree; 136 137 138 // ******************************************************************************************** 139 // ******************************************************************************************** 140 // Constructor - com.sun.source.tree 141 // ******************************************************************************************** 142 // ******************************************************************************************** 143 144 145 /** 146 * <EMBED CLASS="defs" DATA-KIND=NestedType DATA-ENTITY=ClassTree> 147 * <EMBED CLASS='external-html' DATA-FILE-ID=RC_DESCRIPTION> 148 * @param ct <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_TREE> 149 * @param util <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_UTIL> 150 */ 151 public NestedType(ClassTree ct, TreeUtils util) 152 { 153 super( 154 util, // TreeUtils 155 ct, // com.sun.source.Tree.ClassTree instance 156 ct.getModifiers(), // Annotations **AND** public, static, final 157 ct.getSimpleName().toString(), // Name of the class - NEED TO DEBUG THIS !!! 158 Entity.INNER_CLASS, 159 null // BODY SHOULDN'T BE NULL, BUT IT IS FOR NOW!!! 160 ); 161 162 163 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 164 // Generic Type Parametes 165 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 166 167 // List<? extends TypeParameterTree> genericTypeParams = ct.getTypeParameters(); 168 @SuppressWarnings("unchecked") 169 List<TypeParameterTree> genericTypeParams = 170 (List<TypeParameterTree>) ct.getTypeParameters(); 171 172 if ((genericTypeParams == null) || (genericTypeParams.size() > 0)) 173 this.genericTypeParameters = EMPTY_READONLY_LIST; 174 175 else this.genericTypeParameters = new ReadOnlyArrayList<String>( 176 genericTypeParams, 177 (TypeParameterTree tpt) -> tpt.toString().trim(), 178 genericTypeParams.size() 179 ); 180 181 182 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 183 // Implements Clause 184 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 185 186 // List<? extends Tree> implementedTypes = ct.getImplementsClause(); 187 @SuppressWarnings("unchecked") 188 List<Tree> implementedTypes = (List<Tree>) ct.getImplementsClause(); 189 190 if ((implementedTypes == null) || (implementedTypes.size() == 0)) 191 this.implementedTypesJOW = EMPTY_READONLY_LIST; 192 193 else this.implementedTypesJOW = new ReadOnlyArrayList<String>( 194 implementedTypes, 195 (Tree t) -> StrSource.typeToJavaIdentifier(t.toString().trim()).trim(), 196 implementedTypes.size() 197 ); 198 199 200 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 201 // Extends Clause 202 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 203 204 // this.extendedTypesJOW = PJSHelper.getExtendedTypes(ct); 205 Tree t = ct.getExtendsClause(); 206 207 this.extendedTypesJOW = (t == null) 208 ? EMPTY_READONLY_LIST 209 : ReadOnlyList.of(t.toString()); 210 211 212 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 213 // Other Stuff 214 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 215 216 // Reference Hook: This was built using the com.sun.source.tree.ClassTree class, so 217 // there simply isn't a com.github.javaparser.ast.body.TypeDeclaration (so it is 218 // set to null) 219 220 this.classTree = ct; 221 222 // This is the kind of this inner-class / nested-type. This CIET is computed using the 223 // internal-helper method because it is just a big switch-statement. I suspect it is going 224 // to be reused elsewhere, but I am not 100% on that yet. 225 226 // this.ciet = PJSHelper.getCIET(ct); 227 switch (ct.getKind()) 228 { 229 case CLASS: this.ciet = CIET.CLASS; break; 230 case INTERFACE: this.ciet = CIET.INTERFACE; break; 231 case ENUM: this.ciet = CIET.ENUM; break; 232 case ANNOTATION_TYPE: this.ciet = CIET.ANNOTATION; break; 233 234 default: throw new UnreachableError(); 235 } 236 237 /* 238 if (this.ciet == null) 239 Messager.assertFailJavaParser("Unknown Type Declaration: ", this.signature); 240 */ 241 242 // This Helper Computes all three of these fields. 243 Ret3<String, String, String> names = PJSHelper.getInnerTypeNames(ct, util); 244 245 // return new Ret3<>(packageName, nameWithContainer, fullyQualifiedName); 246 this.packageName = names.a; 247 this.nameWithContainer = names.b; 248 this.fullyQualifiedName = names.c; 249 250 // This Helper counts the number of methods and fields in a TypeDeclaration 251 Ret2<Integer, Integer> counts = PJSHelper.countMethodsFields(ct, this.ciet); 252 253 // return new Ret<>(numMethods, numFields); 254 this.numMethods = counts.a; 255 this.numFields = counts.b; 256 } 257 258 259 // ************************************************************************************* 260 // ************************************************************************************* 261 // toString() 262 // ************************************************************************************* 263 // ************************************************************************************* 264 265 266 /** 267 * Generates a {@code String} of this {@code nested-type}, with most information included. 268 * 269 * @return A printable {@code String} of this {@code nested-type}. 270 * 271 * @see PF 272 * @see #toString(int) 273 * @see StrCSV#toCSV(String[], boolean, boolean, Integer) 274 */ 275 public String toString() 276 { 277 return 278 "Name: [" + name + "]\n" + 279 "With Container: [" + nameWithContainer + "]\n" + 280 "Kind: [" + ciet.toString() + "]\n" + 281 "Signature: [" + 282 StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" + 283 284 // "Type Parameters:".length() ==> 16 (17=16+1) 285 printedTypeParameters(17) + 286 287 "Modifiers: [" + 288 StrCSV.toCSV(modifiers, true, true, null) + "]\n" + 289 290 // This will **NEVER** be null - unless 'this' instance was built from an HTML File, 291 // rather than a source-code file. Instances like that are only used temporarily, and 292 // are garbage collected instantly. Do this check anyway (just in case). 293 294 "Location: " + ((this.location == null) 295 ? "null" 296 : ('[' + this.location.quickSummary() + ']')); 297 } 298 299 /** 300 * This class expects a flags that has been masked using the constant ({@code public, static, 301 * final int}) fields of class {@link PF}. Please view this class for more information about 302 * the flags available for modifying the return-value of this {@code toString()} method. 303 * 304 * @param flags These are the toString flags from class PF ("Print Flags"). View available 305 * flags listed in class {@link PF}. 306 * 307 * @return A printable {@code String} of this method, with comment information included as well. 308 * 309 * @see StrCSV#toCSV(String[], boolean, boolean, Integer) 310 * @see #toString() 311 * @see PF 312 */ 313 public String toString(int flags) 314 { 315 boolean color = (flags & UNIX_COLORS) > 0; 316 String nameTitle = "Nested " + ciet.toString(); 317 318 // 7 ==> " Name: ".length() 319 int LEN = nameTitle.length() + 7; 320 321 return 322 printedName(nameTitle, LEN, color) + 323 StringParse.rightSpacePad("Fully Qualified:", LEN) + '[' + fullyQualifiedName + "]\n" + 324 StringParse.rightSpacePad("With Container:", LEN) + '[' + nameWithContainer + "]\n" + 325 printedSignature(LEN, color) + 326 printedTypeParameters(LEN) + 327 printedModifiers(LEN) + 328 printedExtendsImplements(LEN) + 329 printedMethodField(LEN, color) + 330 printedLocation(LEN, color, (flags & BRIEF_LOCATION) > 0) + 331 332 // The previous method does not add a '\n' end to the end of the returned string 333 // This is optional, it adds a '\n' AT THE BEGINNING if it is included 334 335 printedComments(LEN, color, (flags & JAVADOC_COMMENTS) > 0); 336 } 337 338 private String printedMethodField(int numSpaces, boolean color) 339 { 340 return 341 StringParse.rightSpacePad("Num Methods:", numSpaces) + 342 '[' + (color ? BGREEN : "") + numMethods + (color ? RESET : "") + "]\n" + 343 StringParse.rightSpacePad("Num Fields:", numSpaces) + 344 '[' + (color ? BGREEN : "") + numFields + (color ? RESET : "") + "]\n"; 345 } 346 347 private String printedExtendsImplements(int LEN) 348 { 349 return 350 (((this.extendedTypesJOW != null) && (this.extendedTypesJOW.size() > 0)) 351 ? (StringParse.rightSpacePad("Extends:", LEN) + '[' + 352 StrCSV.toCSV(extendedTypesJOW, true, false, null) + "]\n") 353 : "") + 354 (((this.implementedTypesJOW != null) && (this.implementedTypesJOW.size() > 0)) 355 ? (StringParse.rightSpacePad("Implements:", LEN) + '[' + 356 StrCSV.toCSV(implementedTypesJOW, true, false, null) + "]\n") 357 : ""); 358 } 359 360 private String printedTypeParameters(int numSpaces) 361 { 362 if ((this.genericTypeParameters == null) || (this.genericTypeParameters.size() == 0)) 363 return ""; 364 365 return 366 StringParse.rightSpacePad("Type-Parameters:", numSpaces) + 367 '[' + StrCSV.toCSV(genericTypeParameters, true, true, MAX_STR_LEN) + "]\n"; 368 } 369 370 371 // ************************************************************************************* 372 // ************************************************************************************* 373 // Clone, CompareTo & Equals Stuff 374 // ************************************************************************************* 375 // ************************************************************************************* 376 377 378 /** 379 * Java's {@code interface Comparable<T>} requirements. This does a very simple comparison 380 * using the two nested-types's {@code 'name'} field. 381 * 382 * @param nt Any other {@code Nested-Type} to be compared to {@code 'this'} 383 * 384 * @return An integer that fulfills Java's 385 * {@code interface Comparable<NestedType>, public boolean compareTo(NestedType nt)} method 386 * requirements. 387 */ 388 public int compareTo(NestedType nt) 389 { return (this == nt) ? 0 : this.name.compareTo(nt.name); } 390 391 /** 392 * This <I>should be called an "atypical version" of </I> the usual {@code equals(Object 393 * other)} method. This version of equals merely compares the name of the field defined. The 394 * presumption here is that the definition of a 'field' only has meaning - <I>at all</I> - 395 * inside the context of a {@code class, interface, } or {@code enumerated-type} where that 396 * field is defined. Since inside any {@code '.java'} source-code file, there may only be one 397 * field with a given name, this method shall return {@code TRUE} whenever the field being 398 * compared also has the same name. 399 * 400 * @param other This may be any other field. It is <I><B>strongly suggested</B></I> that 401 * {@code 'other'} be a field defined in the same {@code '.java'} source-code file as 402 * {@code 'this'} field. 403 * 404 * @return This method returns {@code TRUE} when {@code 'this'} instance of {@code Field} has 405 * the same {@code 'name'} as the name-field of input-parameter {@code 'other'} 406 */ 407 public boolean equals(NestedType other) 408 { return this.name.equals(other.name); } 409}