aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt57
-rw-r--r--plugins/base/src/test/kotlin/model/JavaTest.kt37
2 files changed, 75 insertions, 19 deletions
diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
index d98559e5..1fbe06f7 100644
--- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
@@ -502,11 +502,21 @@ class DefaultPsiToDocumentableTranslator(
} ?: PropertyContainer.empty()
private fun getBound(type: PsiType): Bound {
- fun bound() = when (type) {
+ //We would like to cache most of the bounds since it is not common to annotate them,
+ //but if this is the case, we treat them as 'one of'
+ fun PsiType.cacheBoundIfHasNoAnnotation(f: (List<Annotations.Annotation>) -> Bound): Bound {
+ val annotations = this.annotations.toList().toListOfAnnotations()
+ return if (annotations.isNotEmpty()) f(annotations)
+ else cachedBounds.getOrPut(canonicalText) {
+ f(annotations)
+ }
+ }
+
+ return when (type) {
is PsiClassReferenceType ->
type.resolve()?.let { resolved ->
when {
- resolved.qualifiedName == "java.lang.Object" -> JavaObject(type.annotations())
+ resolved.qualifiedName == "java.lang.Object" -> type.cacheBoundIfHasNoAnnotation { annotations -> JavaObject(annotations.annotations()) }
resolved is PsiTypeParameter -> {
TypeParameter(
dri = DRI.from(resolved),
@@ -514,6 +524,7 @@ class DefaultPsiToDocumentableTranslator(
extra = type.annotations()
)
}
+
Regex("kotlin\\.jvm\\.functions\\.Function.*").matches(resolved.qualifiedName ?: "") ||
Regex("java\\.util\\.function\\.Function.*").matches(
resolved.qualifiedName ?: ""
@@ -522,33 +533,41 @@ class DefaultPsiToDocumentableTranslator(
type.parameters.map { getProjection(it) },
extra = type.annotations()
)
- else -> GenericTypeConstructor(
- DRI.from(resolved),
- type.parameters.map { getProjection(it) },
- extra = type.annotations()
- )
+
+ else -> {
+ // cache types that have no annotation and no type parameter
+ // since we cache only by name and type parameters depend on context
+ val typeParameters = type.parameters.map { getProjection(it) }
+ if (typeParameters.isEmpty())
+ type.cacheBoundIfHasNoAnnotation { annotations ->
+ GenericTypeConstructor(
+ DRI.from(resolved),
+ typeParameters,
+ extra = annotations.annotations()
+ )
+ }
+ else
+ GenericTypeConstructor(
+ DRI.from(resolved),
+ typeParameters,
+ extra = type.annotations()
+ )
+ }
}
} ?: UnresolvedBound(type.presentableText, type.annotations())
+
is PsiArrayType -> GenericTypeConstructor(
DRI("kotlin", "Array"),
listOf(getProjection(type.componentType)),
extra = type.annotations()
)
+
is PsiPrimitiveType -> if (type.name == "void") Void
- else PrimitiveJavaType(type.name, type.annotations())
- is PsiImmediateClassType -> JavaObject(type.annotations())
+ else type.cacheBoundIfHasNoAnnotation { annotations -> PrimitiveJavaType(type.name, annotations.annotations()) }
+ is PsiImmediateClassType ->
+ type.cacheBoundIfHasNoAnnotation { annotations -> JavaObject(annotations.annotations()) }
else -> throw IllegalStateException("${type.presentableText} is not supported by PSI parser")
}
-
- //We would like to cache most of the bounds since it is not common to annotate them,
- //but if this is the case, we treat them as 'one of'
- return if (type.annotations.toList().toListOfAnnotations().isEmpty()) {
- cachedBounds.getOrPut(type.canonicalText) {
- bound()
- }
- } else {
- bound()
- }
}
diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt
index 0abaf1b1..47a25943 100644
--- a/plugins/base/src/test/kotlin/model/JavaTest.kt
+++ b/plugins/base/src/test/kotlin/model/JavaTest.kt
@@ -143,6 +143,43 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") {
) {
with((this / "java" / "Foo").cast<DClass>()) {
generics counts 1
+ generics[0].dri.classNames equals "Foo"
+ (functions[0].type as? TypeParameter)?.dri?.run {
+ packageName equals "java"
+ name equals "Foo"
+ callable?.name equals "foo"
+ }
+ }
+ }
+ }
+
+ @Test
+ fun typeParameterIntoDifferentClasses2596() {
+ inlineModelTest(
+ """
+ |class GenericDocument { }
+ |public interface DocumentClassFactory<T> {
+ | String getSchemaName();
+ | GenericDocument toGenericDocument(T document);
+ | T fromGenericDocument(GenericDocument genericDoc);
+ |}
+ |
+ |public final class DocumentClassFactoryRegistry {
+ | public <T> DocumentClassFactory<T> getOrCreateFactory(T documentClass) {
+ | return null;
+ | }
+ |}
+ """, configuration = configuration
+ ) {
+ with((this / "java" / "DocumentClassFactory").cast<DInterface>()) {
+ generics counts 1
+ generics[0].dri.classNames equals "DocumentClassFactory"
+ }
+ with((this / "java" / "DocumentClassFactoryRegistry").cast<DClass>()) {
+ functions.forEach {
+ (it.type as GenericTypeConstructor).dri.classNames equals "DocumentClassFactory"
+ ((it.type as GenericTypeConstructor).projections[0] as TypeParameter).dri.classNames equals "DocumentClassFactoryRegistry"
+ }
}
}
}