001package Torello.JavaDoc; 002 003 004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 005// Standard-Java Imports 006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 007 008import java.util.*; 009 010import java.io.IOException; 011import java.util.function.Consumer; 012 013 014// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 015// Java-HTML Imports 016// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 017 018import Torello.Java.*; 019 020import static Torello.Java.C.*; 021import static Torello.JavaDoc.PF.*; 022 023import Torello.Java.Additional.Ret2; 024 025import Torello.Java.ReadOnly.ReadOnlyList; 026import Torello.Java.ReadOnly.ReadOnlyArrayList; 027 028 029// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 030// JDUInternal 031// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 032 033import Torello.JavaDoc.Messager.Messager; 034 035import Torello.JDUInternal.Annotations.EntityAnnotations.Mirror.EntityAnnotationMirrors; 036import Torello.JDUInternal.Annotations.EntityAnnotations.EntityAnnotationData; 037 038import Torello.JDUInternal.Parse.Java.Location.LocationBuilder1; 039import Torello.JDUInternal.Parse.Java.Location.LocationBuilder2; 040 041// NOTE: Here is the Code that uses LocationBuilder1 and 2... It tells you which of the two 042// is applied, and when, and why... 043// 044// this.location = (entity == Entity.INNER_CLASS) 045// ? LocationBuilder2.build(util, tree, util.getJavaDocCommentTree(tree)) 046// : LocationBuilder1.build(...) 047 048 049// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 050// The new Source-Code Parser: com.sun.source.* 051// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 052 053import com.sun.source.util.*; 054import com.sun.source.tree.*; 055import com.sun.source.doctree.*; 056 057 058/** 059 * <B CLASS=JDDescLabel>Reflection Class:</B> 060 * 061 * <BR />Common-Root Ancestor Class of all Bridge Data-Classes. 062 * 063 * <BR /><BR /> 064 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DECLARATION> 065 */ 066@JDHeaderBackgroundImg 067public abstract class Declaration implements java.io.Serializable 068{ 069 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 070 public static final long serialVersionUID = 1; 071 072 /** 073 * For the purposes of passing these around to different parts of the code, every one of these 074 * are given a unique ID. This id is unique for a method, whether it was parsed from a detail 075 * or a summary section. This id is (probably) not useful outside of the HTML Processor 076 * Classes. 077 * 078 * <BR /><BR /><B CLASS=JDDescLabel>ID Clone:</B> 079 * 080 * <BR />If a subclass of {@code Declaration} is cloned, then this {@code id} field is also 081 * cloned / copied. 082 */ 083 public final int id; 084 085 // The id is just created using this counter. 086 private static int idCounter = 1; 087 088 // Used for Modifiers and other Empty ReadOnlyLists's of String 089 static final ReadOnlyList<String> EMPTY_READONLY_LIST = ReadOnlyList.of(); 090 091 /** 092 * This returns the {@code String} that is to be sent to the Syntax {@link HiLiter}. This is 093 * the code inserted into the "HiLited Code" Part (at the end) of a Details Entry on a Java-Doc 094 * Web Page. 095 * 096 * <BR /><BR />On the part of a Java-Doc Web-Page having a "Method Detail", the Method's 097 * HiLited Source-Code body is obtained by the Upgrader-Logic using this here method. 098 * 099 * <BR /><BR /><B CLASS=JDDescLabel>Sub-Class Return Values:</B> 100 * 101 * <BR />This method is overloaded by all sub-classes, and returns values as follows: 102 * 103 * <BR /><BR /><UL CLASS=JDUL> 104 * <LI>{@link Method} will return its {@link Callable#body} field.</LI> 105 * <LI>{@link Constructor} will return its {@link Callable#body} field.</LI> 106 * <LI>{@link Field} will return the {@link #signature} field</LI> 107 * <LI>{@link EnumConstant} will return the {@link #signature} field</LI> 108 * <LI>{@link AnnotationElem} will return the {@link #signature} field</LI> 109 * <LI>{@link NestedType} will always return null</LI> 110 * </UL> 111 * 112 * @return The {@code String} that is ultimately sent to the Syntax HiLiter, and inserted 113 * into a Java Doc page. 114 * 115 * This is package-private, and isn't useful enough to put into the API - this is used 116 * internally, only. 117 */ 118 abstract String codeHiLiteString(); 119 120 // Package-Private. This only processes Java-Doc Upgrader Annotations. Any other Annotations 121 // which are placed on a Detail-Element can be found in: 122 // 123 // public ReadOnlyList<String> annotations 124 // 125 // However, they will just be the "Raw Sting" version of the Annotation. No More, No Less 126 127 public final EntityAnnotationMirrors jduAnnotationMirrors; 128 129 130 // ******************************************************************************************** 131 // ******************************************************************************************** 132 // Basic String-Fields 133 // ******************************************************************************************** 134 // ******************************************************************************************** 135 136 137 /** 138 * The <B>Name</B> of the java {@link Field}, {@link Method}, {@code Constructor}, 139 * {@link EnumConstant} or {@link AnnotationElem}. This will be a <B>simple, standard</B> 140 * 'Java Identifier'. 141 * 142 * <BR /><BR />Note that the name of a {@code Constructor} (for-example) is always just the 143 * name of the class. 144 * 145 * <BR /><BR />This field will never be null. 146 */ 147 public final String name; 148 149 /** 150 * The complete, declared <B>Signature</B> (as a {@code String}) of the {@link Method}, 151 * {@link Field}, {@link Constructor}, {@link EnumConstant} or {@link AnnotationElem}. 152 * 153 * <BR /><BR />This field would never be null. 154 */ 155 public final String signature; 156 157 /** 158 * The <B>Java Doc Comment</B> of this <B>'{@link Entity}'</B> ({@link Field}, {@link Method}, 159 * {@code Constructor}, {@link EnumConstant}, {@link AnnotationElem} or {@link NestedType}) as 160 * a {@code String} - if one exists. The Java Doc Comment is the one defined directly above 161 * the {@code Declaration}. 162 * 163 * <BR /><BR />If this <CODE>Entity</CODE> / Member ({@code Field, Method, Constructor} etc...) 164 * did not have a Java Doc Comment placed on it, <I>then this field {@code 'jdComment'} will be 165 * {@code null}.</I> 166 */ 167 public final String jdComment; 168 169 /** 170 * The <B>Body</B> of this <B>'{@link Entity}'</B> ({@link Field}, {@link Method}, 171 * {@code Constructor}, {@link EnumConstant}, {@link AnnotationElem} or {@link NestedType}) as 172 * a {@code String} - if one exists. 173 * 174 * <BR /><BR />If this <CODE>Entity</CODE> / Member ({@code Field, Method, Constructor} etc...) 175 * did not have a body, <I>then this field {@code 'body'} will be {@code null}.</I> 176 * 177 * <BR /><BR />The {@code 'body'} of a {@code Method} or {@code Constructor} is exactly the 178 * code that comprises it. If the method is {@code abstract}, then the method will not have a 179 * body, and in such cases this field will be null. If this member / entity is a {@link Field} 180 * then the body is the initializer of the {@code Field}. Again, if there were no initializer 181 * for the field, then {@code 'body'} would also be null. 182 */ 183 public final String body; 184 185 186 // ******************************************************************************************** 187 // ******************************************************************************************** 188 // Non-Basic Fields 189 // ******************************************************************************************** 190 // ******************************************************************************************** 191 192 193 /** 194 * This just stores the type of {@link Entity} this is. For sub-classes instances of 195 * {@link Declaration} which are {@link Method}, this field will be equal to 196 * {@link Entity#METHOD}. For instances of the {@link Field} sub-class, this will equal 197 * {@link Entity#FIELD}, and so on and so forth. 198 * 199 * <BR /><BR />Mostly, this makes code easier to read when used along-side <B>if-statements</B> 200 * or <B>switch-statements</B>. This field somewhat akin to {@code Declaration.getClass()} 201 * (when retrieving the specific {@code Declaration} sub-class type). 202 * 203 * <BR /><BR /><B CLASS=JDDescLabel>Reminder:</B> 204 * 205 * <BR />Both this class, and sub-class {@code Callable} are declared {@code abstract}, and 206 * only instances of Method, Field, Constructor, etc... can be instantiated. Only 207 * non-{@code abstract} implementations of this class need to worry about assigning this field 208 * to any real-value. 209 */ 210 public final Entity entity; 211 212 /** Location instance that contains character-locations within the original Java Source-File */ 213 public final Location location; 214 215 216 // ******************************************************************************************** 217 // ******************************************************************************************** 218 // ReadOnlyList<String> Fields 219 // ******************************************************************************************** 220 // ******************************************************************************************** 221 222 223 /** 224 * The {@code 'modifiers'} placed on this {@code Declaration}, including {@code String's} 225 * such as: {@code public, static, final} etc... 226 */ 227 public ReadOnlyList<String> modifiers; 228 229 /** <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DECL_ANNOT> */ 230 public ReadOnlyList<String> annotations; 231 232 233 // ******************************************************************************************** 234 // ******************************************************************************************** 235 // Constructor - com.sun.source.tree 236 // ******************************************************************************************** 237 // ******************************************************************************************** 238 239 240 // package-private: Only used by subclasses. 241 Declaration( 242 final EntityAnnotationData ead, 243 final TreeUtils util, 244 final Tree tree, 245 final ModifiersTree mt, 246 final String name, 247 final Entity entity, 248 final Tree body 249 ) 250 { 251 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 252 // Pre-Liminary 253 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 254 255 this.id = idCounter++; 256 this.name = name; 257 this.entity = entity; 258 259 260 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 261 // The Annotations Placed on this Declaration 262 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 263 // 264 // NOTE: For EnumConstant's, the passed Modifiers-Tree is just null! 265 266 // List<? extends AnnotationTree> annotList = ... 267 @SuppressWarnings("unchecked") 268 final List<AnnotationTree> annotList = (mt == null) 269 ? null 270 : (List<AnnotationTree>) mt.getAnnotations(); 271 272 if ((annotList == null) || (annotList.size() == 0)) 273 this.annotations = EMPTY_READONLY_LIST; 274 275 else this.annotations = new ReadOnlyArrayList<String> 276 (annotList, (AnnotationTree at) -> at.toString().trim(), annotList.size()); 277 278 279 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 280 // The Modifiers that Flag this Declaration (private, public, static, final, etc...) 281 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 282 // 283 // NOTE: For EnumConstant's, the passed Modifiers-Tree is just null! 284 285 final Set<javax.lang.model.element.Modifier> modSet = (mt == null) 286 ? null 287 : mt.getFlags(); 288 289 if ((modSet == null) || (modSet.size() == 0)) 290 this.modifiers = EMPTY_READONLY_LIST; 291 292 else this.modifiers = new ReadOnlyArrayList<String> 293 (modSet, (javax.lang.model.element.Modifier m) -> m.toString().trim(), modSet.size()); 294 295 296 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 297 // Location 298 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 299 300 this.location = (entity == Entity.INNER_CLASS) 301 302 ? LocationBuilder2.build(util, tree, util.getJavaDocCommentTree(tree)) 303 304 : LocationBuilder1.build( 305 util, tree, util.getJavaDocCommentTree(tree), body, 306 (entity == Entity.FIELD) ? body : null 307 ); 308 309 310 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 311 // This can now, officially, be set (now that the location has been constructed) 312 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 313 314 Messager.setDeclaration(this); 315 316 317 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 318 // Now the String's 319 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 320 321 this.signature = util.srcFileAsStr.substring 322 (this.location.signatureStartPos, this.location.signatureEndPos); 323 324 this.jdComment = (this.location.jdcStartPos == -1) 325 ? null 326 : util.srcFileAsStr.substring(this.location.jdcStartPos, this.location.jdcEndPos); 327 328 this.body = (this.location.bodyStartPos == -1) 329 ? null 330 : util.srcFileAsStr.substring(this.location.bodyStartPos, this.location.bodyEndPos); 331 332 333 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 334 // The JavaDoc-Upgrader SPECIFIC Annotations. These are handled & Processed by JDU 335 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 336 337 if ((annotList == null) || (annotList.size() == 0)) 338 this.jduAnnotationMirrors = EntityAnnotationMirrors.EMPTY_MIRROR; 339 340 341 // Because `this.signature` is passed to this constructor, this whole invocation has to be 342 // at the end of the method, instead of above - where the annotations were processed! 343 // 344 // NOTE: The `annotList` variable was created way above, at the top of this constructor! 345 346 else this.jduAnnotationMirrors = (entity != Entity.INNER_CLASS) 347 ? new EntityAnnotationMirrors(annotList, this.signature, ead) 348 : EntityAnnotationMirrors.EMPTY_MIRROR; 349 } 350 351 352 // ******************************************************************************************** 353 // ******************************************************************************************** 354 // Constructor - synthetic methods 355 // ******************************************************************************************** 356 // ******************************************************************************************** 357 358 359 // Used only by the Callable Subclass, for building instances of derived/synthetic methods 360 // and constructors. (For instance, an enum has 'valueOf()' and 'values()') 361 // These methods do not have a location or a jdComment or even a body to hilite 362 363 Declaration(String name, Entity entity, String signature) 364 { 365 this.id = idCounter++; 366 this.name = name; 367 this.entity = entity; 368 this.modifiers = EMPTY_READONLY_LIST; 369 this.annotations = EMPTY_READONLY_LIST; 370 this.signature = signature; 371 this.jduAnnotationMirrors = EntityAnnotationMirrors.EMPTY_MIRROR; 372 373 // Since this constructor is only used for "Synthetic Methods" (barely ever used), it is no 374 // big deal to just assign these null; 375 376 this.location = null; 377 this.jdComment = null; 378 this.body = null; 379 } 380 381 // Not private - used by sub-classes 382 Declaration(Declaration d) 383 { 384 this.id = d.id; 385 this.annotations = d.annotations; 386 this.modifiers = d.modifiers; 387 this.name = d.name; 388 this.signature = d.signature; 389 this.jdComment = d.jdComment; 390 this.body = d.body; 391 this.entity = d.entity; 392 this.location = d.location; 393 this.jduAnnotationMirrors = d.jduAnnotationMirrors; 394 } 395 396 397 // ******************************************************************************************** 398 // ******************************************************************************************** 399 // Package-Private toString-HELPERS: Used by all subclasses 'toString(int flags)' methods 400 // ******************************************************************************************** 401 // ******************************************************************************************** 402 403 404 Ret2<Boolean, Boolean> jowFlags(int flags) 405 { 406 boolean onlyJOW = (flags & JOW_INSTEAD) > 0; 407 boolean addJOW = (flags & JOW_ALSO) > 0; 408 409 // "onlyJOW" has a higher FLAG-PRECEDENCY 410 if (onlyJOW && addJOW) addJOW = false; 411 412 return new Ret2<>(addJOW, onlyJOW); 413 } 414 415 String printedName(String entity, int numSpaces, boolean color) 416 { 417 return 418 StringParse.rightSpacePad(entity + " Name:", numSpaces) + 419 "[" + (color ? BCYAN : "") + name + (color ? RESET : "") + "]\n"; 420 } 421 422 String printedSignature(int numSpaces, boolean color) 423 { 424 return 425 StringParse.rightSpacePad("Signature:", numSpaces) + 426 "[" + (color ? BYELLOW : "") + 427 StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + 428 (color ? RESET : "") + "]\n"; 429 } 430 431 String printedDeclaration(int numSpaces, boolean color) 432 { 433 return 434 StringParse.rightSpacePad("Declaration:", numSpaces) + 435 "[" + (color ? BYELLOW : "") + 436 StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + 437 (color ? RESET : "") + "]\n"; 438 } 439 440 String printedModifiers(int numSpaces) 441 { 442 return 443 StringParse.rightSpacePad("Modifiers:", numSpaces) + 444 "[" + StrCSV.toCSV(modifiers, true, true, null) + "]\n"; 445 } 446 447 String printedComments(int numSpaces, boolean color, boolean comments) 448 { 449 if (! comments) 450 return ""; 451 452 else if (jdComment == null) return 453 "\n" + 454 StringParse.rightSpacePad("JD Comments:", numSpaces) + 455 (color ? BRED : "") + "None Available / Not Included" + (color ? RESET : ""); 456 457 else return 458 "\n" + 459 StringParse.rightSpacePad("JD Comments:", numSpaces) + 460 "[" + 461 (color ? BGREEN : "") + 462 StrPrint.abbrevEndRDSF(jdComment, MAX_STR_LEN, true) + 463 (color ? RESET : "") + 464 "]"; 465 } 466 467 // NOTE: This is always the last item printed to the output-string. This line *DOES NOT* end 468 // with a new-line '\n' character. 469 470 String printedLocation(int numSpaces, boolean color, boolean briefLocation) 471 { 472 if (location == null) return StringParse.rightSpacePad("Location:", numSpaces) + "null"; 473 474 if (briefLocation) return color 475 ? 476 (StringParse.rightSpacePad("Location:", numSpaces) + 477 "[" + 478 "signature-line=" + BRED + this.location.signatureStartLine + RESET + ", " + 479 "javadoc-line=" + BRED + this.location.jdcStartLine + RESET + ", " + 480 "body-line=" + BRED + this.location.bodyStartLine + RESET + 481 "]") 482 : 483 (StringParse.rightSpacePad("Location:", numSpaces) + 484 "[" + 485 "signature-line=" + this.location.signatureStartLine + ", " + 486 "javadoc-line=" + this.location.jdcStartLine + ", " + 487 "body-line=" + this.location.bodyStartLine + 488 ']'); 489 490 String spaces = StringParse.nChars(' ', numSpaces); 491 492 if (color) return 493 StringParse.rightSpacePad("Location:", numSpaces) + 494 "JavaDocComment: [" + 495 "startPos=" + BRED + location.jdcStartPos + RESET + ", " + 496 "endPos=" + BRED + location.jdcEndPos + RESET + ", " + 497 "startLine=" + BRED + location.jdcStartLine + RESET + ", " + 498 "endLine=" + BRED + location.jdcEndLine + RESET + ", " + 499 "startCol=" + BRED + location.jdcStartCol + RESET + ", " + 500 "endCol=" + BRED + location.jdcEndCol + RESET + "]\n" + 501 502 spaces + "Signature: [" + 503 "startPos=" + BRED + location.signatureStartPos + RESET + ", " + 504 "endPos=" + BRED + location.signatureEndPos + RESET + ", " + 505 "startLine=" + BRED + location.signatureStartLine + RESET + ", " + 506 "endLine=" + BRED + location.signatureEndLine + RESET + ", " + 507 "startCol=" + BRED + location.signatureStartCol + RESET + ", " + 508 "endCol=" + BRED + location.signatureEndCol + RESET + "]\n" + 509 510 spaces + "Body: [" + 511 "startPos=" + BRED + location.bodyStartPos + RESET + ", " + 512 "endPos=" + BRED + location.bodyEndPos + RESET + ", " + 513 "startLine=" + BRED + location.bodyStartLine + RESET + ", " + 514 "endLine=" + BRED + location.bodyEndLine + RESET + ", " + 515 "startCol=" + BRED + location.bodyStartCol + RESET + ", " + 516 "endCol=" + BRED + location.bodyEndCol + RESET + "]"; 517 518 else return 519 StringParse.rightSpacePad("Location:", numSpaces) + 520 "JavaDocComment: [" + 521 "startPos=" + location.jdcStartPos + ", " + 522 "endPos=" + location.jdcEndPos + ", " + 523 "startLine=" + location.jdcStartLine + ", " + 524 "endLine=" + location.jdcEndLine + ", " + 525 "startCol=" + location.jdcStartCol + ", " + 526 "endCol=" + location.jdcEndCol + "]\n" + 527 528 spaces + "Signature: [" + 529 "startPos=" + location.signatureStartPos + ", " + 530 "endPos=" + location.signatureEndPos + ", " + 531 "startLine=" + location.signatureStartLine + ", " + 532 "endLine=" + location.signatureEndLine + ", " + 533 "startCol=" + location.signatureStartCol + ", " + 534 "endCol=" + location.signatureEndCol + "]\n" + 535 536 spaces + "Body: [" + 537 "startPos=" + location.bodyStartPos + ", " + 538 "endPos=" + location.bodyEndPos + ", " + 539 "startLine=" + location.bodyStartLine + ", " + 540 "endLine=" + location.bodyEndLine + ", " + 541 "startCol=" + location.bodyStartCol + ", " + 542 "endCol=" + location.bodyEndCol + "]"; 543 } 544 545 546 // ******************************************************************************************** 547 // ******************************************************************************************** 548 // Abstract-Class ToString 549 // ******************************************************************************************** 550 // ******************************************************************************************** 551 552 553 /** 554 * Dummy Method. Overriden by Concrete Sub-Classes. 555 * @see Method#toString() 556 * @see Field#toString() 557 * @see Constructor#toString() 558 */ 559 public String toString() 560 { return "Declaration is Abstract, all Concrete Sub-Classes Override this method."; } 561 562 /** 563 * Dummy Method. Overriden by Concrete Sub-Classes. 564 * @see Method#toString(int) 565 * @see Field#toString(int) 566 * @see Constructor#toString(int) 567 */ 568 public String toString(int flags) 569 { return "Declaration is Abstract, all Concrete Sub-Classes Override this method."; } 570 571 572 // ******************************************************************************************** 573 // ******************************************************************************************** 574 // A.I. Token-Stream Generator-Method 575 // ******************************************************************************************** 576 // ******************************************************************************************** 577 578 579 /** 580 * Chat-GPT and me wrote a Token-Stream Generator-Method that can be used for creating the 581 * List-Data that needs to be sent to the Embeddings-Generator for creating an Embeddings-RAG 582 * using my Reflection-Classes. 583 * 584 * @return A proper list of "Chunked Tokens" that may be sent to the Open-AI REST-API to 585 * generate an Embeddings-Vector 586 */ 587 public abstract ReadOnlyList<ReadOnlyList<String>> getTokenStreams(); 588}