blob: e52240cbd0a64d8eb43adee13894081ac1a5da74 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devsite.renderer.converters
import com.google.devsite.components.impl.DefaultAnnotation
import com.google.devsite.renderer.Language
import com.google.devsite.renderer.impl.paths.FilePathProvider
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.AnnotationParameterValue
import org.jetbrains.dokka.model.AnnotationValue
import org.jetbrains.dokka.model.Annotations
import org.jetbrains.dokka.model.Annotations.Annotation
import org.jetbrains.dokka.model.ArrayValue
import org.jetbrains.dokka.model.ClassValue
import org.jetbrains.dokka.model.EnumValue
import org.jetbrains.dokka.model.StringValue
import org.jetbrains.dokka.model.properties.WithExtraProperties
import com.google.devsite.components.symbols.Annotation as AnnotationComponent
/** @return the components for the provided dokka model annotations */
internal fun List<Annotation>.annotationComponents(
pathProvider: FilePathProvider,
displayLanguage: Language,
nullable: Boolean
): List<AnnotationComponent> {
val injectedAnnotations = mutableListOf<Annotation>()
if (nullable && !isNullable()) {
injectedAnnotations += Annotation(DRI("androidx.annotation", "Nullable"), emptyMap())
}
return (this + injectedAnnotations).filter { annotation ->
shouldDocumentAnnotation(annotation, displayLanguage)
}.map { annotation ->
val type = pathProvider.linkForReference(annotation.dri)
val params = annotation.params.map { (name, contents) ->
AnnotationComponent.Parameter(name, contents.toComponent())
}
DefaultAnnotation(AnnotationComponent.Params(type, params))
}
}
/** @return true if the `@Nullable` annotation is present, false otherwise */
internal fun List<Annotation>.isNullable(): Boolean = any { it.dri.classNames == "Nullable" }
/** @return true if the `@Deprecated` annotation is present, false otherwise */
internal fun List<Annotation>.isDeprecated(): Boolean = any { it.isDeprecated() }
/** @return the complete list of annotations for this type */
internal fun WithExtraProperties<*>.annotations(): List<Annotation> {
return extra.allOfType<Annotations>().flatMap { annotations ->
annotations.directAnnotations.values.singleOrNull() ?: emptyList()
}
}
/** @return true if the `@Deprecated` annotation is present, false otherwise */
internal fun Annotation.isDeprecated(): Boolean = dri.classNames == "Deprecated"
/** @return true if a developer would find this annotation useful, false otherwise */
private fun shouldDocumentAnnotation(annotation: Annotation, language: Language): Boolean {
// Not useful to developers
val isSuppressAnnotation = annotation.dri.classNames == "Suppress" ||
annotation.dri.classNames == "SuppressWarnings"
val isKotlinJvmAnnotation = annotation.dri.packageName == "kotlin.jvm"
// Surfaced separately
val isDeprecatedAnnotation = annotation.isDeprecated()
val isNullabilityAnnotation = annotation.dri.classNames == "NonNull" ||
annotation.dri.classNames == "Nullable"
return !isSuppressAnnotation &&
!isKotlinJvmAnnotation &&
!isDeprecatedAnnotation &&
// Keep nullability annotations for Java
(language == Language.JAVA || !isNullabilityAnnotation)
}
internal fun AnnotationParameterValue.toComponent(): String = when (this) {
is StringValue -> "\"$value\""
is EnumValue -> enumName
is ClassValue -> className
is ArrayValue -> value.joinToString(prefix = "[", postfix = "]") { it.toComponent() }
is AnnotationValue -> TODO("Unknown use case.")
}