Repository: Kotlin/dokka (kotlin)

Issue:
Supertypes for java source use incorrect generics
Sample java source:
```java
class Bar<T> {}
public class Foo extends Bar<String> {}
```

The super class type of `Foo` should be `Bar<String>`, but the `supertypes` on the `DClass` for `Foo` instead includes the type `Bar<T>`, using the type parameter from the definition of `Bar` instead of the concrete type used in `Foo`'s definition.

(This is handled correctly for kotlin source.)

Pull request:
The processing of supertypes for java source would convert `PsiClassType`s to `PsiClass`es while creating `AncestryNode`s. This meant that the type parameters used for the supertypes were from the `PsiClass` definition instead of the `PsiClassType` usage like they should be.

For example, in the following java code:
```
class Bar<T> {}
public class Foo extends Bar<String> {}
```

The super class type of `Foo` should be `Bar<String>`. When processing the supertypes of `Foo`, the `PsiClassType` representing `Bar<String>` was converted to a `PsiClass`. The `PsiClass` reflects the definition of `Bar`, so `Bar<T>` became the super class type instead of `Bar<String>`.

Fixes: #3996

Patch:
diff --git a/dokka-subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt b/dokka-subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt
index 299bae3705..5270078948 100644
--- a/dokka-subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt
+++ b/dokka-subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt
@@ -107,15 +107,11 @@ internal class DokkaPsiParser(
              * - superMethods
              * - superFieldsKeys
              * - superKeys
+             *
+             * First processes the list of [PsiClassType]s to add their methods and fields to the maps mentioned above,
+             * then filters the list to return a pair of the optional superclass type and a list of interface types.
              */
-            /**
-             * Caution! This method mutates
-             * - superMethodsKeys
-             * - superMethods
-             * - superFieldsKeys
-             * - superKeys
-             */
-            fun Array<PsiClassType>.getSuperTypesPsiClasses(): List<Pair<PsiClass, JavaClassKindTypes>> {
+            fun List<PsiClassType>.getSuperclassAndInterfaces(): Pair<PsiClassType?, List<PsiClassType>> {
                 forEach { type ->
                     type.resolve()?.let {
                         val definedAt = DRI.from(it)
@@ -137,38 +133,61 @@ internal class DokkaPsiParser(
                         }
                     }
                 }
-                return filter { !it.shouldBeIgnored }.mapNotNull { supertypePsi ->
+                val supertypesToKinds = filter { !it.shouldBeIgnored }.mapNotNull { supertypePsi ->
                     supertypePsi.resolve()?.let { supertypePsiClass ->
                         val javaClassKind = when {
                             supertypePsiClass.isInterface -> JavaClassKindTypes.INTERFACE
                             else -> JavaClassKindTypes.CLASS
                         }
-                        supertypePsiClass to javaClassKind
+                        supertypePsi to javaClassKind
                     }
                 }
+                val (superclassPairs, interfacePairs) =
+                    supertypesToKinds.partition { it.second == JavaClassKindTypes.CLASS }
+                return superclassPairs.firstOrNull()?.first to interfacePairs.map { it.first}
             }
 
-            fun traversePsiClassForAncestorsAndInheritedMembers(psiClass: PsiClass): AncestryNode {
-                val (classes, interfaces) = psiClass.superTypes.getSuperTypesPsiClasses()
-                    .partition { it.second == JavaClassKindTypes.CLASS }
+            /**
+             * Creates an [AncestryNode] for the [type] given the list of all [supertypes].
+             *
+             * Also processes all super methods and fields using the getSuperclassAndInterfaces function defined above.
+             */
+            fun createAncestryNode(type: GenericTypeConstructor, supertypes: List<PsiClassType>): AncestryNode {
+                fun createAncestryNodeForPsiClassType(psiClassType: PsiClassType): AncestryNode {
+                    return createAncestryNode(
+                        type = GenericTypeConstructor(
+                            DRI.from(psiClassType.resolve()!!),
+                            psiClassType.parameters.map { getProjection(it) }
+                        ),
+                        supertypes = psiClassType.superTypes.filterIsInstance<PsiClassType>()
+                    )
+                }
 
+                val (superclass, interfaces) = supertypes.getSuperclassAndInterfaces()
                 return AncestryNode(
-                    typeConstructor = GenericTypeConstructor(
-                        DRI.from(psiClass),
-                        psiClass.typeParameters.map { typeParameter ->
-                            TypeParameter(
-                                dri = DRI.from(typeParameter),
-                                name = typeParameter.name.orEmpty(),
-                                extra = typeParameter.annotations()
-                            )
-                        }
-                    ),
-                    superclass = classes.singleOrNull()?.first?.let(::traversePsiClassForAncestorsAndInheritedMembers),
-                    interfaces = interfaces.map { traversePsiClassForAncestorsAndInheritedMembers(it.first) }
+                    typeConstructor = type,
+                    superclass = superclass?.let(::createAncestryNodeForPsiClassType),
+                    interfaces = interfaces.map { createAncestryNodeForPsiClassType(it) }
                 )
             }
 
-            val ancestry: AncestryNode = traversePsiClassForAncestorsAndInheritedMembers(this)
+            // Creates the AncestryNode for this class. The AncestryNodes for this class's supertypes will be done using
+            // PsiClassTypes, not PsiClasses. This is important because the type parameters used in the class hierarchy
+            // should reflect the usage in the extends/implements clause, not the type parameters in the supertype
+            // class definitions, which the PsiClasses would use.
+            val ancestry = createAncestryNode(
+                type = GenericTypeConstructor(
+                    DRI.from(this),
+                    typeParameters.map { typeParameter ->
+                        TypeParameter(
+                            dri = DRI.from(typeParameter),
+                            name = typeParameter.name.orEmpty(),
+                            extra = typeParameter.annotations()
+                        )
+                    }
+                ),
+                supertypes = superTypes.toList()
+            )
 
             val (regularFunctions, accessors) = splitFunctionsAndAccessors(psi.fields, psi.methods)
             val (regularSuperFunctions, superAccessors) = splitFunctionsAndAccessors(


Test patch:
diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/model/JavaTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/model/JavaTest.kt
index 5d76cc843a..32a207c149 100644
--- a/dokka-subprojects/plugin-base/src/test/kotlin/model/JavaTest.kt
+++ b/dokka-subprojects/plugin-base/src/test/kotlin/model/JavaTest.kt
@@ -80,6 +80,26 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") {
         }
     }
 
+    @Test fun allImplementedInterfacesWithGenericsInJava() {
+        inlineModelTest(
+            """
+            |interface Highest<H> { }
+            |interface Lower<L> extends Highest<L> { }
+            |class Extendable { }
+            |class Tested<T> extends Extendable implements Lower<T> { }
+        """, configuration = configuration){
+            with((this / "java" / "Tested").cast<DClass>()){
+                val implementedInterfaces = extra[ImplementedInterfaces]?.interfaces?.entries?.single()?.value!!
+                implementedInterfaces.map { it.dri.sureClassNames }.sorted() equals listOf("Highest", "Lower").sorted()
+                for (implementedInterface in implementedInterfaces) {
+                    // The type parameter T from Tested should be used for each interface, not the type parameters in
+                    // the interface definitions.
+                    assertEquals((implementedInterface.projections.single() as TypeParameter).name, "T")
+                }
+            }
+        }
+    }
+
     @Test fun multipleClassInheritanceWithInterface() {
         inlineModelTest(
             """
@@ -94,6 +114,25 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") {
         }
     }
 
+    @Test
+    fun interfaceWithGeneric() {
+        inlineModelTest(
+            """
+            |interface Bar<T> {}
+            |public class Foo implements Bar<String> {}
+            """, configuration = configuration
+        ) {
+            with((this / "java" / "Foo").cast<DClass>()) {
+                val interfaceType = supertypes.values.flatten().single()
+                assertEquals(interfaceType.kind, JavaClassKindTypes.INTERFACE)
+                assertEquals(interfaceType.typeConstructor.dri.classNames, "Bar")
+                // The interface type should be Bar<String>, and not use Bar<T> like the interface definition
+                val generic = interfaceType.typeConstructor.projections.single() as GenericTypeConstructor
+                assertEquals(generic.dri.classNames, "String")
+            }
+        }
+    }
+
     @Test
     fun superClass() {
         inlineModelTest(
@@ -110,6 +149,25 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") {
         }
     }
 
+    @Test
+    fun superclassWithGeneric() {
+        inlineModelTest(
+            """
+            |class Bar<T> {}
+            |public class Foo extends Bar<String> {}
+            """, configuration = configuration
+        ) {
+            with((this / "java" / "Foo").cast<DClass>()) {
+                val superclassType = supertypes.values.flatten().single()
+                assertEquals(superclassType.kind, JavaClassKindTypes.CLASS)
+                assertEquals(superclassType.typeConstructor.dri.classNames, "Bar")
+                // The superclass type should be Bar<String>, and not use Bar<T> like the class definition
+                val generic = superclassType.typeConstructor.projections.single() as GenericTypeConstructor
+                assertEquals(generic.dri.classNames, "String")
+            }
+        }
+    }
+
     @Test
     fun arrayType() {
         inlineModelTest(