On Wed, 27 Mar 2024 17:19:35 GMT, Pavel Rappo <pra...@openjdk.org> wrote:

> Creating a link to a constructor or a method or comparing constructors or 
> methods __does not__ factor in type parameters. When constructors or methods 
> are overloaded and differ only in type parameters -- a situation which is 
> absent in JDK API, but present elsewhere -- that causes significant defects, 
> such as:
> 
>   - missing entries in summary tables, lists and indexes,
>   - duplicating links in the table of contents.
> 
> This PR fixes those defects, and the fix is two-fold. Firstly, we update 
> comparators to consider type parameters. That takes care of missing 
> constructors and methods. Secondly, we update id (anchor) and link generation 
> to always use the "erased" notation. That takes care of duplicating links.
> 
> What's the "erased" notation? Suppose we have the following method:
> 
>     <T extends String> T m(T arg)
> 
> The current notation refers to it as `m(T)`. That works fine until there's no 
> other method, such as
> 
>     <T> T m(T arg)
> 
> In which case, the current notation will produce a collision: `m(T)`. By 
> contrast, the erased notation for those two methods is `m(java.lang.String)` 
> and `m(java.lang.Object)` respectively. No collision.
> 
> While longer, I believe that the erased notation is collision-proof. Why? 
> Because [JLS 8.4.2][] says that "it is a compile-time error to declare two 
> methods with override-equivalent signatures in a class". Which means that for 
> any two constructors or methods the erasure of their signatures must differ, 
> or else it won't compile.
> 
> The change is pretty straightforward, except for some test fallout that 
> required attention.
> 
> [JLS 8.4.2]: 
> https://docs.oracle.com/javase/specs/jls/se22/html/jls-8.html#jls-8.4.2

Generally, great work!

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
 line 173:

> 171:      */
> 172:     HtmlId forMember(TypeElement typeElement, ExecutableElement member) {
> 173:         return HtmlId.of(forErasure(typeElement, 
> member).replaceAll("\\s", ""));

I suggest adding something like an `@apiNote` to explain why the `typeElement` 
may not be the same as the enclosing element, if the enclosing element is not 
documented.   The hint is there in your use of the word `documented` -- and 
while that's true, it's also very subtle.

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
 line 215:

> 213:         var parameterTypes = ((ExecutableType) utils.typeUtils
> 214:                 .erasure(utils.asInstantiatedMethodType(site, 
> executable)))
> 215:                 .getParameterTypes();

Cool expression!

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
 line 216:

> 214:                 .erasure(utils.asInstantiatedMethodType(site, 
> executable)))
> 215:                 .getParameterTypes();
> 216:         var stv = new SimpleTypeVisitor9<String, Void>() {

It's conventional to use the latest visitor, which in this case is 
`SimpleTypeVisitor14`, but that being said, there seems to be no obvious 
difference between 9 and 14.

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
 line 219:

> 217:             @Override
> 218:             public String visitArray(ArrayType t, Void p) {
> 219:                 return visit(t.getComponentType()) + 
> utils.getDimension(t);

Obviously, `utils.getDimension()` harkens back to the old (JDK 8-era) doclet, 
but even the current implementation of that method could use some TLC. But 
that's not your problem here.

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
 line 233:

> 231:         };
> 232:         return executable.getSimpleName() + parameterTypes.stream()
> 233:                 .map(stv::visit)

Why do you need this (`stv::visit`) -- does the normal `.toString` for an array 
type not do the right thing?

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
 line 442:

> 440:     public HtmlId forPreviewSection(Element el) {
> 441:         return HtmlId.of("preview-" + switch (el.getKind()) {
> 442:             case CONSTRUCTOR, METHOD -> forMember((TypeElement) 
> el.getEnclosingElement(), (ExecutableElement) el).name(); // fixme?

what needs fixing?

test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java line 70:

> 68:                     public abstract <T extends X> T m(T arg);
> 69:                     public abstract <T extends Y> T m(T arg);
> 70:                 }

Nice example

test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java line 81:

> 79:         checkExit(Exit.OK);
> 80:         // constructors
> 81:         checkOutput("Foo.html", true, """

This is not wrong, and so does not need to be changed, but situations like this 
are why `checkOrder` was added -- so that you can "spot check" the significant 
parts of the summary table (such as the links to the detail entries), without 
all the surrounding table-related stuff.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/18519#issuecomment-2023718905
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541583038
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541810596
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541759579
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541826582
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541830699
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541828519
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541573333
PR Review Comment: https://git.openjdk.org/jdk/pull/18519#discussion_r1541838818

Reply via email to