| /* |
| * 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.") |
| } |