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