aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/build.gradle4
-rw-r--r--core/src/main/kotlin/DokkaBootstrapImpl.kt76
-rw-r--r--core/src/main/kotlin/Formats/AnalysisComponents.kt45
-rw-r--r--core/src/main/kotlin/Formats/FormatDescriptor.kt43
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt214
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt344
-rw-r--r--core/src/main/kotlin/Java/JavadocParser.kt402
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt188
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt534
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt33
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt473
-rw-r--r--core/src/main/kotlin/Languages/CommonLanguageService.kt84
-rw-r--r--core/src/main/kotlin/Languages/LanguageService.kt41
-rw-r--r--core/src/main/kotlin/Model/PackageDocs.kt136
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModules.kt82
-rw-r--r--core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt2
16 files changed, 3 insertions, 2698 deletions
diff --git a/core/build.gradle b/core/build.gradle
index f3fe35e4..ea1ab325 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -21,7 +21,7 @@ allprojects {
}
dependencies {
- compile project(":integration")
+// compile project(":integration")
compile project(path: ":coreDependencies", configuration: "shadow")
compile "org.jetbrains.kotlin:kotlin-stdlib:$bundled_kotlin_compiler_version"
@@ -50,7 +50,7 @@ dependencies {
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-js:$bundled_kotlin_compiler_version"
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-common:$bundled_kotlin_compiler_version"
- testImplementation project(":core:testApi")
+// testImplementation project(":core:testApi")
testCompile ideaRT()
}
diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt
deleted file mode 100644
index b48b62d4..00000000
--- a/core/src/main/kotlin/DokkaBootstrapImpl.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.gson.Gson
-import org.jetbrains.dokka.DokkaConfiguration.PackageOptions
-
-import java.util.function.BiConsumer
-
-
-fun parsePerPackageOptions(arg: String): List<PackageOptions> {
- if (arg.isBlank()) return emptyList()
-
- return arg.split(";").map { it.split(",") }.map {
- val prefix = it.first()
- if (prefix == "")
- throw IllegalArgumentException("Please do not register packageOptions with all match pattern, use global settings instead")
- val args = it.subList(1, it.size)
- val deprecated = args.find { it.endsWith("deprecated") }?.startsWith("+") ?: true
- val reportUndocumented = args.find { it.endsWith("warnUndocumented") }?.startsWith("+") ?: true
- val privateApi = args.find { it.endsWith("privateApi") }?.startsWith("+") ?: false
- val suppress = args.find { it.endsWith("suppress") }?.startsWith("+") ?: false
- PackageOptionsImpl(prefix, includeNonPublic = privateApi, reportUndocumented = reportUndocumented, skipDeprecated = !deprecated, suppress = suppress)
- }
-}
-
-class DokkaBootstrapImpl : DokkaBootstrap {
-
- private class DokkaProxyLogger(val consumer: BiConsumer<String, String>) : DokkaLogger {
- override fun info(message: String) {
- consumer.accept("info", message)
- }
-
- override fun warn(message: String) {
- consumer.accept("warn", message)
- }
-
- override fun error(message: String) {
- consumer.accept("error", message)
- }
- }
-
- lateinit var generator: DokkaGenerator
- val gson = Gson()
-
- fun configure(logger: DokkaLogger, configuration: DokkaConfigurationImpl) = with(configuration) {
-
- fun defaultLinks(config: PassConfigurationImpl): List<ExternalDocumentationLinkImpl> {
- val links = mutableListOf<ExternalDocumentationLinkImpl>()
- if (!config.noJdkLink)
- links += DokkaConfiguration.ExternalDocumentationLink
- .Builder("https://docs.oracle.com/javase/${config.jdkVersion}/docs/api/")
- .build() as ExternalDocumentationLinkImpl
-
- if (!config.noStdlibLink)
- links += DokkaConfiguration.ExternalDocumentationLink
- .Builder("https://kotlinlang.org/api/latest/jvm/stdlib/")
- .build() as ExternalDocumentationLinkImpl
- return links
- }
-
- val configurationWithLinks =
- configuration.copy(passesConfigurations =
- passesConfigurations
- .map {
- val links: List<ExternalDocumentationLinkImpl> = it.externalDocumentationLinks + defaultLinks(it)
- it.copy(externalDocumentationLinks = links)
- }
- )
-
- generator = DokkaGenerator(configurationWithLinks, logger)
- }
-
- override fun configure(logger: BiConsumer<String, String>, serializedConfigurationJSON: String)
- = configure(DokkaProxyLogger(logger), gson.fromJson(serializedConfigurationJSON, DokkaConfigurationImpl::class.java))
-
- override fun generate() = generator.generate()
-}
diff --git a/core/src/main/kotlin/Formats/AnalysisComponents.kt b/core/src/main/kotlin/Formats/AnalysisComponents.kt
deleted file mode 100644
index d78d4a0c..00000000
--- a/core/src/main/kotlin/Formats/AnalysisComponents.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import com.google.inject.Binder
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.KotlinAsJavaElementSignatureProvider
-import org.jetbrains.dokka.KotlinElementSignatureProvider
-import org.jetbrains.dokka.ElementSignatureProvider
-import org.jetbrains.dokka.Samples.DefaultSampleProcessingService
-import org.jetbrains.dokka.Samples.SampleProcessingService
-import org.jetbrains.dokka.Utilities.bind
-import org.jetbrains.dokka.Utilities.toType
-import kotlin.reflect.KClass
-
-
-interface DefaultAnalysisComponentServices {
- val packageDocumentationBuilderClass: KClass<out PackageDocumentationBuilder>
- val javaDocumentationBuilderClass: KClass<out JavaDocumentationBuilder>
- val sampleProcessingService: KClass<out SampleProcessingService>
- val elementSignatureProvider: KClass<out ElementSignatureProvider>
-}
-
-interface DefaultAnalysisComponent : FormatDescriptorAnalysisComponent, DefaultAnalysisComponentServices {
- override fun configureAnalysis(binder: Binder): Unit = with(binder) {
- bind<ElementSignatureProvider>() toType elementSignatureProvider
- bind<PackageDocumentationBuilder>() toType packageDocumentationBuilderClass
- bind<JavaDocumentationBuilder>() toType javaDocumentationBuilderClass
- bind<SampleProcessingService>() toType sampleProcessingService
- }
-}
-
-
-object KotlinAsJava : DefaultAnalysisComponentServices {
- override val packageDocumentationBuilderClass = KotlinAsJavaDocumentationBuilder::class
- override val javaDocumentationBuilderClass = JavaPsiDocumentationBuilder::class
- override val sampleProcessingService = DefaultSampleProcessingService::class
- override val elementSignatureProvider = KotlinAsJavaElementSignatureProvider::class
-}
-
-
-object KotlinAsKotlin : DefaultAnalysisComponentServices {
- override val packageDocumentationBuilderClass = KotlinPackageDocumentationBuilder::class
- override val javaDocumentationBuilderClass = KotlinJavaDocumentationBuilder::class
- override val sampleProcessingService = DefaultSampleProcessingService::class
- override val elementSignatureProvider = KotlinElementSignatureProvider::class
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/FormatDescriptor.kt b/core/src/main/kotlin/Formats/FormatDescriptor.kt
deleted file mode 100644
index 4bac8aa0..00000000
--- a/core/src/main/kotlin/Formats/FormatDescriptor.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.jetbrains.dokka.Formats
-
-import com.google.inject.Binder
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Utilities.bind
-import org.jetbrains.dokka.Utilities.lazyBind
-import org.jetbrains.dokka.Utilities.toOptional
-import org.jetbrains.dokka.Utilities.toType
-import kotlin.reflect.KClass
-
-
-interface FormatDescriptorAnalysisComponent {
- fun configureAnalysis(binder: Binder)
-}
-
-interface FormatDescriptorOutputComponent {
- fun configureOutput(binder: Binder)
-}
-
-interface FormatDescriptor : FormatDescriptorAnalysisComponent, FormatDescriptorOutputComponent
-
-
-abstract class FileGeneratorBasedFormatDescriptor : FormatDescriptor {
-
- override fun configureOutput(binder: Binder): Unit = with(binder) {
- bind<Generator>() toType NodeLocationAwareGenerator::class
- bind<NodeLocationAwareGenerator>() toType generatorServiceClass
- bind(generatorServiceClass.java) // https://github.com/google/guice/issues/847
-
- bind<LanguageService>() toType languageServiceClass
-
- lazyBind<OutlineFormatService>() toOptional (outlineServiceClass)
- lazyBind<FormatService>() toOptional formatServiceClass
- lazyBind<PackageListService>() toOptional packageListServiceClass
- }
-
- abstract val formatServiceClass: KClass<out FormatService>?
- abstract val outlineServiceClass: KClass<out OutlineFormatService>?
- abstract val generatorServiceClass: KClass<out FileGenerator>
- abstract val packageListServiceClass: KClass<out PackageListService>?
-
- open val languageServiceClass: KClass<out LanguageService> = KotlinLanguageService::class
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt
deleted file mode 100644
index 51d70fbd..00000000
--- a/core/src/main/kotlin/Generation/DokkaGenerator.kt
+++ /dev/null
@@ -1,214 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Guice
-import com.google.inject.Injector
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiJavaFile
-import com.intellij.psi.PsiManager
-import org.jetbrains.dokka.Utilities.DokkaAnalysisModule
-import org.jetbrains.dokka.Utilities.DokkaRunModule
-import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
-import org.jetbrains.kotlin.cli.common.messages.MessageCollector
-import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.MemberDescriptor
-import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer
-import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
-import org.jetbrains.kotlin.utils.PathUtil
-import java.io.File
-
-class DokkaGenerator(
- val dokkaConfiguration: DokkaConfiguration,
- val logger: DokkaLogger
-) {
-
- private val documentationModules: MutableList<DocumentationNodes.Module> = mutableListOf()
- private val globalInjector = Guice.createInjector(DokkaRunModule(dokkaConfiguration))
-
-
- fun generate() = with(dokkaConfiguration) {
-
-
- for (pass in passesConfigurations) {
- val documentationModule = DocumentationNodes.Module(pass.moduleName)
- appendSourceModule(pass, documentationModule)
- documentationModules.add(documentationModule)
- }
- }
-
- private fun appendSourceModule(
- passConfiguration: DokkaConfiguration.PassConfiguration,
- documentationModule: DocumentationNodes.Module
- ) = with(passConfiguration) {
-
- val sourcePaths = passConfiguration.sourceRoots.map { it.path }
- val environment = createAnalysisEnvironment(sourcePaths, passConfiguration)
-
- logger.info("Module: $moduleName")
- logger.info("Output: ${File(dokkaConfiguration.outputDir)}")
- logger.info("Sources: ${sourcePaths.joinToString()}")
- logger.info("Classpath: ${environment.classpath.joinToString()}")
-
- logger.info("Analysing sources and libraries... ")
- val startAnalyse = System.currentTimeMillis()
-
- val defaultPlatformAsList = passConfiguration.targets
- val defaultPlatformsProvider = object : DefaultPlatformsProvider {
- override fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String> {
-// val containingFilePath = descriptor.sourcePsi()?.containingFile?.virtualFile?.canonicalPath
-// ?.let { File(it).absolutePath }
-// val sourceRoot = containingFilePath?.let { path -> sourceRoots.find { path.startsWith(it.path) } }
- if (descriptor is MemberDescriptor && descriptor.isExpect) {
- return defaultPlatformAsList.take(1)
- }
- return /*sourceRoot?.platforms ?: */defaultPlatformAsList
- }
- }
-
- val injector = globalInjector.createChildInjector(
- DokkaAnalysisModule(environment, dokkaConfiguration, defaultPlatformsProvider, passConfiguration, logger)
- )
-
- buildDocumentationModule(
- injector,
- documentationModule,
- { isNotSample(it, passConfiguration.samples) },
- includes
- )
-
- val timeAnalyse = System.currentTimeMillis() - startAnalyse
- logger.info("done in ${timeAnalyse / 1000} secs")
-
- Disposer.dispose(environment)
- }
-
- fun createAnalysisEnvironment(
- sourcePaths: List<String>,
- passConfiguration: DokkaConfiguration.PassConfiguration
- ): AnalysisEnvironment {
- val environment = AnalysisEnvironment(DokkaMessageCollector(logger), passConfiguration.analysisPlatform)
-
- environment.apply {
- if (analysisPlatform == Platform.jvm) {
- addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
- }
- // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath())
- for (element in passConfiguration.classpath) {
- addClasspath(File(element))
- }
-
- addSources(sourcePaths)
- addSources(passConfiguration.samples)
-
- loadLanguageVersionSettings(passConfiguration.languageVersion, passConfiguration.apiVersion)
- }
-
- return environment
- }
-
- private fun isNotSample(file: PsiFile, samples: List<String>): Boolean {
- val sourceFile = File(file.virtualFile!!.path)
- return samples.none { sample ->
- val canonicalSample = File(sample).canonicalPath
- val canonicalSource = sourceFile.canonicalPath
- canonicalSource.startsWith(canonicalSample)
- }
- }
-}
-
-class DokkaMessageCollector(val logger: DokkaLogger) : MessageCollector {
- override fun clear() {
- seenErrors = false
- }
-
- private var seenErrors = false
-
- override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
- if (severity == CompilerMessageSeverity.ERROR) {
- seenErrors = true
- }
- logger.error(MessageRenderer.PLAIN_FULL_PATHS.render(severity, message, location))
- }
-
- override fun hasErrors() = seenErrors
-}
-
-fun buildDocumentationModule(
- injector: Injector,
- documentationModule: DocumentationNodes.Module,
- filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true },
- includes: List<String> = listOf()
-) {
-
- val coreEnvironment = injector.getInstance(KotlinCoreEnvironment::class.java)
- val fragmentFiles = coreEnvironment.getSourceFiles().filter(filesToDocumentFilter)
-
- val resolutionFacade = injector.getInstance(DokkaResolutionFacade::class.java)
- val analyzer = resolutionFacade.getFrontendService(LazyTopDownAnalyzer::class.java)
- analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, fragmentFiles)
-
- val fragments = fragmentFiles.mapNotNull { resolutionFacade.resolveSession.getPackageFragment(it.packageFqName) }
- .distinct()
-
- val packageDocs = injector.getInstance(PackageDocs::class.java)
- for (include in includes) {
- packageDocs.parse(include, fragments)
- }
-
- parseJavaPackageDocs(packageDocs, coreEnvironment)
-
- with(injector.getInstance(DocumentationBuilder::class.java)) {
- documentationModule.appendFragments(
- fragments,
- injector.getInstance(PackageDocumentationBuilder::class.java)
- )
-
- propagateExtensionFunctionsToSubclasses(fragments, resolutionFacade)
- }
-
- val javaFiles = coreEnvironment.getJavaSourceFiles().filter(filesToDocumentFilter)
- with(injector.getInstance(JavaDocumentationBuilder::class.java)) {
- javaFiles.map { appendFile(it, documentationModule, packageDocs.packageContent) }
- }
-}
-
-fun parseJavaPackageDocs(packageDocs: PackageDocs, coreEnvironment: KotlinCoreEnvironment) {
- val contentRoots = coreEnvironment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS)
- ?.filterIsInstance<JavaSourceRoot>()
- ?.map { it.file }
- ?: listOf()
- contentRoots.forEach { root ->
- root.walkTopDown().filter { it.name == "overview.html" }.forEach {
- packageDocs.parseJava(it.path, it.relativeTo(root).parent.replace("/", "."))
- }
- }
-}
-
-
-fun KotlinCoreEnvironment.getJavaSourceFiles(): List<PsiJavaFile> {
- val sourceRoots = configuration.get(CLIConfigurationKeys.CONTENT_ROOTS)
- ?.filterIsInstance<JavaSourceRoot>()
- ?.map { it.file }
- ?: listOf()
-
- val result = arrayListOf<PsiJavaFile>()
- val localFileSystem = VirtualFileManager.getInstance().getFileSystem("file")
- sourceRoots.forEach { sourceRoot ->
- sourceRoot.absoluteFile.walkTopDown().forEach {
- val vFile = localFileSystem.findFileByPath(it.path)
- if (vFile != null) {
- val psiFile = PsiManager.getInstance(project).findFile(vFile)
- if (psiFile is PsiJavaFile) {
- result.add(psiFile)
- }
- }
- }
- }
- return result
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
deleted file mode 100644
index d3fc7048..00000000
--- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
+++ /dev/null
@@ -1,344 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.openapi.util.text.StringUtil
-import com.intellij.psi.*
-import com.intellij.psi.impl.JavaConstantExpressionEvaluator
-import com.intellij.psi.util.InheritanceUtil
-import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation
-import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
-import org.jetbrains.kotlin.asJava.elements.KtLightElement
-import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.psi.KtModifierListOwner
-
-fun getSignature(element: PsiElement?) = when(element) {
- is PsiPackage -> element.qualifiedName
- is PsiClass -> element.qualifiedName
- is PsiField -> element.containingClass!!.qualifiedName + "$" + element.name
- is PsiMethod ->
- methodSignature(element)
- is PsiParameter -> {
- val method = (element.parent.parent as PsiMethod)
- methodSignature(method)
- }
- else -> null
-}
-
-private fun methodSignature(method: PsiMethod): String {
- return method.containingClass!!.qualifiedName + "$" + method.name + "(" +
- method.parameterList.parameters.map { it.type.typeSignature() }.joinToString(",") + ")"
-}
-
-private fun PsiType.typeSignature(): String = when(this) {
- is PsiArrayType -> "Array((${componentType.typeSignature()}))"
- is PsiPrimitiveType -> "kotlin." + canonicalText.capitalize()
- else -> mapTypeName(this)
-}
-
-private fun mapTypeName(psiType: PsiType): String = when (psiType) {
- is PsiPrimitiveType -> psiType.canonicalText
- is PsiClassType -> psiType.resolve()?.qualifiedName ?: psiType.className
- is PsiEllipsisType -> mapTypeName(psiType.componentType)
- is PsiArrayType -> "kotlin.Array"
- else -> psiType.canonicalText
-}
-
-interface JavaDocumentationBuilder {
- fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>)
-}
-
-class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
- private val passConfiguration: DokkaConfiguration.PassConfiguration
- private val refGraph: NodeReferenceGraph
- private val docParser: JavaDocumentationParser
- private val documentationBuilder: DocumentationBuilder
-
- @Inject constructor(
- documentationBuilder: DocumentationBuilder,
- refGraph: NodeReferenceGraph,
- logger: DokkaLogger,
- signatureProvider: ElementSignatureProvider,
- externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
- ) {
- this.passConfiguration = documentationBuilder.passConfiguration
- this.documentationBuilder = documentationBuilder
- this.refGraph = refGraph
- this.docParser = JavadocParser(refGraph, logger, signatureProvider, externalDocumentationLinkResolver)
- }
-
- constructor(documentationBuilder: DocumentationBuilder, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
- this.passConfiguration = documentationBuilder.passConfiguration
- this.refGraph = refGraph
- this.docParser = docParser
- this.documentationBuilder = documentationBuilder
- }
-
- override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
- if (skipFile(file) || file.classes.all { skipElement(it) }) {
- return
- }
- val packageNode = documentationBuilder.findOrCreatePackageNode(module, file.packageName, emptyMap(), refGraph)
- appendClasses(packageNode, file.classes)
- }
-
- fun appendClasses(packageNode: DocumentationNode, classes: Array<PsiClass>) {
- packageNode.appendChildren(classes) { build() }
- }
-
- fun register(element: PsiElement, node: DocumentationNode) {
- val signature = getSignature(element)
- if (signature != null) {
- refGraph.register(signature, node)
- }
- }
-
- fun link(node: DocumentationNode, element: PsiElement?) {
- val qualifiedName = getSignature(element)
- if (qualifiedName != null) {
- refGraph.link(node, qualifiedName, RefKind.Link)
- }
- }
-
- fun link(element: PsiElement?, node: DocumentationNode, kind: RefKind) {
- val qualifiedName = getSignature(element)
- if (qualifiedName != null) {
- refGraph.link(qualifiedName, node, kind)
- }
- }
-
- fun nodeForElement(element: PsiNamedElement,
- kind: DocumentationNodes,
- name: String = element.name ?: "<anonymous>",
- register: Boolean = false): DocumentationNode {
- val (docComment, deprecatedContent) = docParser.parseDocumentation(element)
- val node = DocumentationNode(name, docComment, kind)
- if (register) register(element, node)
- if (element is PsiModifierListOwner) {
- node.appendModifiers(element)
- val modifierList = element.modifierList
- if (modifierList != null) {
- modifierList.annotations.filter { !ignoreAnnotation(it) }.forEach {
- val annotation = it.build()
- node.append(annotation,
- if (it.qualifiedName == "java.lang.Deprecated") RefKind.Deprecation else RefKind.Annotation)
- }
- }
- }
- return node
- }
-
- fun ignoreAnnotation(annotation: PsiAnnotation) = when(annotation.qualifiedName) {
- "java.lang.SuppressWarnings" -> true
- else -> false
- }
-
- fun <T : Any> DocumentationNode.appendChildren(elements: Array<T>,
- kind: RefKind = RefKind.Member,
- buildFn: T.() -> DocumentationNode) {
- elements.forEach {
- if (!skipElement(it)) {
- append(it.buildFn(), kind)
- }
- }
- }
-
- private fun skipFile(javaFile: PsiJavaFile): Boolean = passConfiguration.effectivePackageOptions(javaFile.packageName).suppress
-
- private fun skipElement(element: Any) =
- skipElementByVisibility(element) ||
- hasSuppressDocTag(element) ||
- skipElementBySuppressedFiles(element)
-
- private fun skipElementByVisibility(element: Any): Boolean =
- element is PsiModifierListOwner &&
- element !is PsiParameter &&
- !(passConfiguration.effectivePackageOptions((element.containingFile as? PsiJavaFile)?.packageName ?: "").includeNonPublic) &&
- (element.hasModifierProperty(PsiModifier.PRIVATE) ||
- element.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) ||
- element.isInternal())
-
- private fun skipElementBySuppressedFiles(element: Any): Boolean =
- element is PsiElement && element.containingFile.virtualFile.path in passConfiguration.suppressedFiles
-
- private fun PsiElement.isInternal(): Boolean {
- val ktElement = (this as? KtLightElement<*, *>)?.kotlinOrigin ?: return false
- return (ktElement as? KtModifierListOwner)?.hasModifier(KtTokens.INTERNAL_KEYWORD) ?: false
- }
-
- fun <T : Any> DocumentationNode.appendMembers(elements: Array<T>, buildFn: T.() -> DocumentationNode) =
- appendChildren(elements, RefKind.Member, buildFn)
-
- fun <T : Any> DocumentationNode.appendDetails(elements: Array<T>, buildFn: T.() -> DocumentationNode) =
- appendChildren(elements, RefKind.Detail, buildFn)
-
- fun PsiClass.build(): DocumentationNode {
- val kind = when {
- isAnnotationType -> DocumentationNodes.AnnotationClass
- isInterface -> DocumentationNodes.Interface
- isEnum -> DocumentationNodes.Enum
- isException() -> DocumentationNodes.Exception
- else -> DocumentationNodes.Class
- }
- val node = nodeForElement(this, kind, register = isAnnotationType)
- superTypes.filter { !ignoreSupertype(it) }.forEach {
- node.appendType(it, DocumentationNodes.Supertype)
- val superClass = it.resolve()
- if (superClass != null) {
- link(superClass, node, RefKind.Inheritor)
- }
- }
- node.appendDetails(typeParameters) { build() }
- node.appendMembers(methods) { build() }
- node.appendMembers(fields) { build() }
- node.appendMembers(innerClasses) { build() }
- register(this, node)
- return node
- }
-
- fun PsiClass.isException() = InheritanceUtil.isInheritor(this, "java.lang.Throwable")
-
- fun ignoreSupertype(psiType: PsiClassType): Boolean =
- psiType.isClass("java.lang.Enum") || psiType.isClass("java.lang.Object")
-
- fun PsiClassType.isClass(qName: String): Boolean {
- val shortName = qName.substringAfterLast('.')
- if (className == shortName) {
- val psiClass = resolve()
- return psiClass?.qualifiedName == qName
- }
- return false
- }
-
- fun PsiField.build(): DocumentationNode {
- val node = nodeForElement(this, nodeKind())
- node.appendType(type)
-
- node.appendConstantValueIfAny(this)
- register(this, node)
- return node
- }
-
- private fun DocumentationNode.appendConstantValueIfAny(field: PsiField) {
- val modifierList = field.modifierList ?: return
- val initializer = field.initializer ?: return
- if (modifierList.hasExplicitModifier(PsiModifier.FINAL) &&
- modifierList.hasExplicitModifier(PsiModifier.STATIC)) {
- val value = JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false)
- val text = when(value) {
- null -> return // No value found
- is String ->
- "\"" + StringUtil.escapeStringCharacters(value) + "\""
- else -> value.toString()
- }
- append(DocumentationNode(text, Content.Empty, DocumentationNodes.Value), RefKind.Detail)
- }
- }
-
- private fun PsiField.nodeKind(): DocumentationNodes = when {
- this is PsiEnumConstant -> DocumentationNodes.EnumItem
- else -> DocumentationNodes.Field
- }
-
- fun PsiMethod.build(): DocumentationNode {
- val node = nodeForElement(this, nodeKind(),
- if (isConstructor) "<init>" else name)
-
- if (!isConstructor) {
- node.appendType(returnType)
- }
- node.appendDetails(parameterList.parameters) { build() }
- node.appendDetails(typeParameters) { build() }
- register(this, node)
- return node
- }
-
- private fun PsiMethod.nodeKind(): DocumentationNodes = when {
- isConstructor -> DocumentationNodes.Constructor
- else -> DocumentationNodes.Function
- }
-
- fun PsiParameter.build(): DocumentationNode {
- val node = nodeForElement(this, DocumentationNodes.Parameter::class)
- node.appendType(type)
- return node
- }
-
- fun PsiTypeParameter.build(): DocumentationNode {
- val node = nodeForElement(this, DocumentationNodes.TypeParameter)
- extendsListTypes.forEach { node.appendType(it, DocumentationNodes.UpperBound) }
- implementsListTypes.forEach { node.appendType(it, DocumentationNodes.UpperBound) }
- return node
- }
-
- fun DocumentationNode.appendModifiers(element: PsiModifierListOwner) {
- val modifierList = element.modifierList ?: return
-
- PsiModifier.MODIFIERS.forEach {
- if (modifierList.hasExplicitModifier(it)) {
- appendTextNode(it, DocumentationNodes.Modifier)
- }
- }
- }
-
- fun DocumentationNode.appendType(psiType: PsiType?, kind: DocumentationNodes = DocumentationNodes.Type) {
- if (psiType == null) {
- return
- }
- append(psiType.build(kind), RefKind.Detail)
- }
-
- fun PsiType.build(kind: DocumentationNodes = DocumentationNodes.Type): DocumentationNode {
- val name = mapTypeName(this)
- val node = DocumentationNode(name, Content.Empty, kind)
- if (this is PsiClassType) {
- node.appendDetails(parameters) { build(DocumentationNodes.Type) }
- link(node, resolve())
- }
- if (this is PsiArrayType && this !is PsiEllipsisType) {
- node.append(componentType.build(DocumentationNodes.Type), RefKind.Detail)
- }
- return node
- }
-
- private fun lookupOrBuildClass(psiClass: PsiClass): DocumentationNode {
- val existing = refGraph.lookup(getSignature(psiClass)!!)
- if (existing != null) return existing
- val new = psiClass.build()
- val packageNode = documentation. findOrCreatePackageNode(null, (psiClass.containingFile as PsiJavaFile).packageName, emptyMap(), refGraph)
- packageNode.append(new, RefKind.Member)
- return new
- }
-
- fun PsiAnnotation.build(): DocumentationNode {
-
- val original = when (this) {
- is KtLightAbstractAnnotation -> clsDelegate
- else -> this
- }
- val node = DocumentationNodes.Annotation(qualifiedName?.substringAfterLast(".") ?: "<?>")
- val psiClass = original.nameReferenceElement?.resolve() as? PsiClass
- if (psiClass != null && psiClass.isAnnotationType) {
- node.append(lookupOrBuildClass(psiClass), RefKind.Link)
- }
- parameterList.attributes.forEach {
- val parameter = DocumentationNodes.Parameter(it.name ?: "value", this.extractDescriptor())
- val value = it.value
- if (value != null) {
- val valueText = (value as? PsiLiteralExpression)?.value as? String ?: value.text
- val valueNode = DocumentationNode(valueText, Content.Empty, DocumentationNodes.Value)
- parameter.append(valueNode, RefKind.Detail)
- }
- node.append(parameter, RefKind.Detail)m
- }
- return node
- }
-}
-
-fun hasSuppressDocTag(element: Any?): Boolean {
- val declaration = (element as? KtLightDeclaration<*, *>)?.kotlinOrigin ?: return false
- return PsiTreeUtil.findChildrenOfType(declaration.docComment, KDocTag::class.java).any { it.knownTag == KDocKnownTag.SUPPRESS }
-}
-
diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt
deleted file mode 100644
index 25a974a3..00000000
--- a/core/src/main/kotlin/Java/JavadocParser.kt
+++ /dev/null
@@ -1,402 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.*
-import com.intellij.psi.impl.source.tree.JavaDocElementType
-import com.intellij.psi.javadoc.*
-import com.intellij.psi.util.PsiTreeUtil
-import com.intellij.util.containers.isNullOrEmpty
-import org.jetbrains.kotlin.utils.keysToMap
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Element
-import org.jsoup.nodes.Node
-import org.jsoup.nodes.TextNode
-import java.net.URI
-
-data class JavadocParseResult(val content: Content, val deprecatedContent: Content?) {
- companion object {
- val Empty = JavadocParseResult(Content.Empty, null)
- }
-}
-
-interface JavaDocumentationParser {
- fun parseDocumentation(element: PsiNamedElement): JavadocParseResult
-}
-
-class JavadocParser(
- private val refGraph: NodeReferenceGraph,
- private val logger: DokkaLogger,
- private val signatureProvider: ElementSignatureProvider,
- private val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
-) : JavaDocumentationParser {
-
- private fun ContentSection.appendTypeElement(signature: String, selector: (DocumentationNode) -> DocumentationNode?) {
- append(LazyContentBlock {
- val node = refGraph.lookupOrWarn(signature, logger)?.let(selector) ?: return@LazyContentBlock emptyList()
- listOf(ContentBlock().apply {
- append(NodeRenderContent(node, LanguageService.RenderMode.SUMMARY))
- symbol(":")
- text(" ")
- })
- })
- }
-
- override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
- val docComment = (element as? PsiDocCommentOwner)?.docComment ?: return JavadocParseResult.Empty
- val result = MutableContent()
- var deprecatedContent: Content? = null
-
- val nodes = convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() }, element)
- val firstParagraphContents = nodes.takeWhile { it !is ContentParagraph }
- val firstParagraph = ContentParagraph()
- if (firstParagraphContents.isNotEmpty()) {
- firstParagraphContents.forEach { firstParagraph.append(it) }
- result.append(firstParagraph)
- }
-
- result.appendAll(nodes.drop(firstParagraphContents.size))
-
- if (element is PsiMethod) {
- val tagsByName = element.searchInheritedTags()
- for ((tagName, tags) in tagsByName) {
- for ((tag, context) in tags) {
- val section = result.addSection(javadocSectionDisplayName(tagName), tag.getSubjectName())
- val signature = signatureProvider.signature(element)
- when (tagName) {
- "param" -> {
- section.appendTypeElement(signature) {
- it.details
- .find { node -> node.kind == NodeKind.Parameter && node.name == tag.getSubjectName() }
- ?.detailOrNull(NodeKind.Type)
- }
- }
- "return" -> {
- section.appendTypeElement(signature) { it.detailOrNull(NodeKind.Type) }
- }
- }
- section.appendAll(convertJavadocElements(tag.contentElements(), context))
- }
- }
- }
-
- docComment.tags.forEach { tag ->
- when (tag.name) {
- "see" -> result.convertSeeTag(tag)
- "deprecated" -> {
- deprecatedContent = Content().apply {
- appendAll(convertJavadocElements(tag.contentElements(), element))
- }
- }
- in tagsToInherit -> {}
- else -> {
- val subjectName = tag.getSubjectName()
- val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName)
-
- section.appendAll(convertJavadocElements(tag.contentElements(), element))
- }
- }
- }
- return JavadocParseResult(result, deprecatedContent)
- }
-
- private val tagsToInherit = setOf("param", "return", "throws")
-
- private data class TagWithContext(val tag: PsiDocTag, val context: PsiNamedElement)
-
- private fun PsiMethod.searchInheritedTags(): Map<String, Collection<TagWithContext>> {
-
- val output = tagsToInherit.keysToMap { mutableMapOf<String?, TagWithContext>() }
-
- fun recursiveSearch(methods: Array<PsiMethod>) {
- for (method in methods) {
- recursiveSearch(method.findSuperMethods())
- }
- for (method in methods) {
- for (tag in method.docComment?.tags.orEmpty()) {
- if (tag.name in tagsToInherit) {
- output[tag.name]!![tag.getSubjectName()] = TagWithContext(tag, method)
- }
- }
- }
- }
-
- recursiveSearch(arrayOf(this))
- return output.mapValues { it.value.values }
- }
-
-
- private fun PsiDocTag.contentElements(): Iterable<PsiElement> {
- val tagValueElements = children
- .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME }
- .dropWhile { it is PsiWhiteSpace }
- .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS }
- return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements
- }
-
- private fun convertJavadocElements(elements: Iterable<PsiElement>, element: PsiNamedElement): List<ContentNode> {
- val doc = Jsoup.parse(expandAllForElements(elements, element))
- return doc.body().childNodes().mapNotNull {
- convertHtmlNode(it)
- }
- }
-
- private fun ContentBlock.appendAll(nodes: List<ContentNode>) {
- nodes.forEach { append(it) }
- }
-
- private fun expandAllForElements(elements: Iterable<PsiElement>, element: PsiNamedElement): String {
- val htmlBuilder = StringBuilder()
- elements.forEach {
- if (it is PsiInlineDocTag) {
- htmlBuilder.append(convertInlineDocTag(it, element))
- } else {
- htmlBuilder.append(it.text)
- }
- }
- return htmlBuilder.toString().trim()
- }
-
- private fun convertHtmlNode(node: Node, insidePre: Boolean = false): ContentNode? {
- if (node is TextNode) {
- val text = if (insidePre) node.wholeText else node.text()
- return ContentText(text)
- } else if (node is Element) {
- val childBlock = createBlock(node, insidePre)
-
- node.childNodes().forEach {
- val child = convertHtmlNode(it, insidePre || childBlock is ContentBlockCode)
- if (child != null) {
- childBlock.append(child)
- }
- }
- return childBlock
- }
- return null
- }
-
- private fun createBlock(element: Element, insidePre: Boolean): ContentBlock = when (element.tagName()) {
- "p" -> ContentParagraph()
- "b", "strong" -> ContentStrong()
- "i", "em" -> ContentEmphasis()
- "s", "del" -> ContentStrikethrough()
- "code" -> if (insidePre) ContentBlock() else ContentCode()
- "pre" -> ContentBlockCode()
- "ul" -> ContentUnorderedList()
- "ol" -> ContentOrderedList()
- "li" -> ContentListItem()
- "a" -> createLink(element)
- "br" -> ContentBlock().apply { hardLineBreak() }
- else -> ContentBlock()
- }
-
- private fun createLink(element: Element): ContentBlock {
- return when {
- element.hasAttr("docref") -> {
- val docref = element.attr("docref")
- ContentNodeLazyLink(docref) { refGraph.lookupOrWarn(docref, logger)}
- }
- element.hasAttr("href") -> {
- val href = element.attr("href")
-
- val uri = try {
- URI(href)
- } catch (_: Exception) {
- null
- }
-
- if (uri?.isAbsolute == false) {
- ContentLocalLink(href)
- } else {
- ContentExternalLink(href)
- }
- }
- element.hasAttr("name") -> {
- ContentBookmark(element.attr("name"))
- }
- else -> ContentBlock()
- }
- }
-
- private fun MutableContent.convertSeeTag(tag: PsiDocTag) {
- val linkElement = tag.linkElement() ?: return
- val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
-
- val valueElement = tag.referenceElement()
- val externalLink = resolveExternalLink(valueElement)
- val text = ContentText(linkElement.text)
-
- val linkSignature by lazy { resolveInternalLink(valueElement) }
- val node = when {
- externalLink != null -> {
- val linkNode = ContentExternalLink(externalLink)
- linkNode.append(text)
- linkNode
- }
- linkSignature != null -> {
- val linkNode =
- ContentNodeLazyLink(
- (tag.valueElement ?: linkElement).text
- ) { refGraph.lookupOrWarn(linkSignature!!, logger) }
- linkNode.append(text)
- linkNode
- }
- else -> text
- }
- seeSection.append(node)
- }
-
- private fun convertInlineDocTag(tag: PsiInlineDocTag, element: PsiNamedElement) = when (tag.name) {
- "link", "linkplain" -> {
- val valueElement = tag.referenceElement()
- val externalLink = resolveExternalLink(valueElement)
- val linkSignature by lazy { resolveInternalLink(valueElement) }
- if (externalLink != null || linkSignature != null) {
- val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text
- val linkTarget = if (externalLink != null) "href=\"$externalLink\"" else "docref=\"$linkSignature\""
- val link = "<a $linkTarget>${labelText.htmlEscape()}</a>"
- if (tag.name == "link") "<code>$link</code>" else link
- } else if (valueElement != null) {
- valueElement.text
- } else {
- ""
- }
- }
- "code", "literal" -> {
- val text = StringBuilder()
- tag.dataElements.forEach { text.append(it.text) }
- val escaped = text.toString().trimStart().htmlEscape()
- if (tag.name == "code") "<code>$escaped</code>" else escaped
- }
- "inheritDoc" -> {
- val result = (element as? PsiMethod)?.let {
- // @{inheritDoc} is only allowed on functions
- val parent = tag.parent
- when (parent) {
- is PsiDocComment -> element.findSuperDocCommentOrWarn()
- is PsiDocTag -> element.findSuperDocTagOrWarn(parent)
- else -> null
- }
- }
- result ?: tag.text
- }
- else -> tag.text
- }
-
- private fun PsiDocTag.referenceElement(): PsiElement? =
- linkElement()?.let {
- if (it.node.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER) {
- PsiTreeUtil.findChildOfType(it, PsiJavaCodeReferenceElement::class.java)
- } else {
- it
- }
- }
-
- private fun PsiDocTag.linkElement(): PsiElement? =
- valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
-
- private fun resolveExternalLink(valueElement: PsiElement?): String? {
- val target = valueElement?.reference?.resolve()
- if (target != null) {
- return externalDocumentationLinkResolver.buildExternalDocumentationLink(target)
- }
- return null
- }
-
- private fun resolveInternalLink(valueElement: PsiElement?): String? {
- val target = valueElement?.reference?.resolve()
- if (target != null) {
- return signatureProvider.signature(target)
- }
- return null
- }
-
- fun PsiDocTag.getSubjectName(): String? {
- if (name == "param" || name == "throws" || name == "exception") {
- return valueElement?.text
- }
- return null
- }
-
- private fun PsiMethod.findSuperDocCommentOrWarn(): String {
- val method = findFirstSuperMethodWithDocumentation(this)
- if (method != null) {
- val descriptionElements = method.docComment?.descriptionElements?.dropWhile {
- it.text.trim().isEmpty()
- } ?: return ""
-
- return expandAllForElements(descriptionElements, method)
- }
- logger.warn("No docs found on supertype with {@inheritDoc} method ${this.name} in ${this.containingFile.name}:${this.lineNumber()}")
- return ""
- }
-
-
- private fun PsiMethod.findSuperDocTagOrWarn(elementToExpand: PsiDocTag): String {
- val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, this)
-
- if (result != null) {
- val (method, tag) = result
-
- val contentElements = tag.contentElements().dropWhile { it.text.trim().isEmpty() }
-
- val expandedString = expandAllForElements(contentElements, method)
-
- return expandedString
- }
- logger.warn("No docs found on supertype for @${elementToExpand.name} ${elementToExpand.getSubjectName()} with {@inheritDoc} method ${this.name} in ${this.containingFile.name}:${this.lineNumber()}")
- return ""
- }
-
- private fun findFirstSuperMethodWithDocumentation(current: PsiMethod): PsiMethod? {
- val superMethods = current.findSuperMethods()
- for (method in superMethods) {
- val docs = method.docComment?.descriptionElements?.dropWhile { it.text.trim().isEmpty() }
- if (!docs.isNullOrEmpty()) {
- return method
- }
- }
- for (method in superMethods) {
- val result = findFirstSuperMethodWithDocumentation(method)
- if (result != null) {
- return result
- }
- }
-
- return null
- }
-
- private fun findFirstSuperMethodWithDocumentationforTag(elementToExpand: PsiDocTag, current: PsiMethod): Pair<PsiMethod, PsiDocTag>? {
- val superMethods = current.findSuperMethods()
- val mappedFilteredTags = superMethods.map {
- it to it.docComment?.tags?.filter { it.name == elementToExpand.name }
- }
-
- for ((method, tags) in mappedFilteredTags) {
- tags ?: continue
- for (tag in tags) {
- val (tagSubject, elementSubject) = when (tag.name) {
- "throws" -> {
- // match class names only for throws, ignore possibly fully qualified path
- // TODO: Always match exactly here
- tag.getSubjectName()?.split(".")?.last() to elementToExpand.getSubjectName()?.split(".")?.last()
- }
- else -> {
- tag.getSubjectName() to elementToExpand.getSubjectName()
- }
- }
-
- if (tagSubject == elementSubject) {
- return method to tag
- }
- }
- }
-
- for (method in superMethods) {
- val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, method)
- if (result != null) {
- return result
- }
- }
- return null
- }
-
-}
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
deleted file mode 100644
index 7c9f2d15..00000000
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ /dev/null
@@ -1,188 +0,0 @@
-package org.jetbrains.dokka.Kotlin
-
-import com.google.inject.Inject
-import com.intellij.psi.PsiDocCommentOwner
-import com.intellij.psi.PsiNamedElement
-import com.intellij.psi.util.PsiTreeUtil
-import org.intellij.markdown.parser.LinkMap
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Samples.SampleProcessingService
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
-import org.jetbrains.kotlin.idea.kdoc.findKDoc
-import org.jetbrains.kotlin.incremental.components.NoLookupLocation
-import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
-import org.jetbrains.kotlin.kdoc.psi.api.KDoc
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.psi.KtElement
-import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
-import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.annotations.argumentValue
-import org.jetbrains.kotlin.resolve.constants.StringValue
-import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
-import org.jetbrains.kotlin.resolve.source.PsiSourceElement
-
-class DescriptorDocumentationParser
-@Inject constructor(
- val options: DokkaConfiguration.PassConfiguration,
- val logger: DokkaLogger,
- val linkResolver: DeclarationLinkResolver,
- val resolutionFacade: DokkaResolutionFacade,
- val refGraph: NodeReferenceGraph,
- val sampleService: SampleProcessingService,
- val signatureProvider: KotlinElementSignatureProvider,
- val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
-) {
- fun parseDocumentation(
- descriptor: DeclarationDescriptor,
- inline: Boolean = false,
- isDefaultNoArgConstructor: Boolean = false
- ): Content =
- parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first
-
- fun parseDocumentationAndDetails(
- descriptor: DeclarationDescriptor,
- inline: Boolean = false,
- isDefaultNoArgConstructor: Boolean = false
- ): Pair<Content, (DocumentationNode) -> Unit> {
- if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) {
- return parseJavadoc(descriptor)
- }
-
- val kdoc = descriptor.findKDoc() ?: findStdlibKDoc(descriptor)
- if (kdoc == null) {
- if (options.effectivePackageOptions(descriptor.fqNameSafe).reportUndocumented && !descriptor.isDeprecated() &&
- descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor &&
- descriptor !is PropertyAccessorDescriptor && !descriptor.isSuppressWarning()) {
- logger.warn("No documentation for ${descriptor.signatureWithSourceLocation()}")
- }
- return Content.Empty to { node -> }
- }
-
- val contextDescriptor =
- (PsiTreeUtil.getParentOfType(kdoc, KDoc::class.java)?.context as? KtDeclaration)
- ?.takeIf { it != descriptor.original.sourcePsi() }
- ?.resolveToDescriptorIfAny()
- ?: descriptor
-
- var kdocText = if (isDefaultNoArgConstructor) {
- getConstructorTagContent(descriptor) ?: kdoc.getContent()
- } else kdoc.getContent()
-
- // workaround for code fence parsing problem in IJ markdown parser
- if (kdocText.endsWith("```") || kdocText.endsWith("~~~")) {
- kdocText += "\n"
- }
- val tree = parseMarkdown(kdocText)
- val linkMap = LinkMap.buildLinkMap(tree.node, kdocText)
- val content = buildContent(
- tree,
- LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) },
- inline
- )
- if (kdoc is KDocSection) {
- val tags = kdoc.getTags()
- tags.forEach {
- when (it.knownTag) {
- KDocKnownTag.SAMPLE ->
- content.append(sampleService.resolveSample(contextDescriptor, it.getSubjectName(), it))
- KDocKnownTag.SEE ->
- content.addTagToSeeAlso(contextDescriptor, it)
- else -> {
- val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName())
- val sectionContent = it.getContent()
- val markdownNode = parseMarkdown(sectionContent)
- buildInlineContentTo(
- markdownNode,
- section,
- LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) })
- }
- }
- }
- }
- return content to { node -> }
- }
-
- private fun getConstructorTagContent(descriptor: DeclarationDescriptor): String? {
- return ((DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.navigationElement as? KtElement) as KtDeclaration).docComment?.findSectionByTag(
- KDocKnownTag.CONSTRUCTOR
- )?.getContent()
- }
-
-
- private fun DeclarationDescriptor.isSuppressWarning(): Boolean {
- val suppressAnnotation = annotations.findAnnotation(FqName(Suppress::class.qualifiedName!!))
- return if (suppressAnnotation != null) {
- @Suppress("UNCHECKED_CAST")
- (suppressAnnotation.argumentValue("names")?.value as List<StringValue>).any { it.value == "NOT_DOCUMENTED" }
- } else containingDeclaration?.isSuppressWarning() ?: false
- }
-
- /**
- * Special case for generating stdlib documentation (the Any class to which the override chain will resolve
- * is not the same one as the Any class included in the source scope).
- */
- fun findStdlibKDoc(descriptor: DeclarationDescriptor): KDocTag? {
- if (descriptor !is CallableMemberDescriptor) {
- return null
- }
- val name = descriptor.name.asString()
- if (name == "equals" || name == "hashCode" || name == "toString") {
- var deepestDescriptor: CallableMemberDescriptor = descriptor
- while (!deepestDescriptor.overriddenDescriptors.isEmpty()) {
- deepestDescriptor = deepestDescriptor.overriddenDescriptors.first()
- }
- if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") {
- val anyClassDescriptors = resolutionFacade.resolveSession.getTopLevelClassifierDescriptors(
- FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE
- )
- anyClassDescriptors.forEach {
- val anyMethod = (it as ClassDescriptor).getMemberScope(listOf())
- .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS) { it == descriptor.name }
- .single()
- val kdoc = anyMethod.findKDoc()
- if (kdoc != null) {
- return kdoc
- }
- }
- }
- }
- return null
- }
-
- fun parseJavadoc(descriptor: DeclarationDescriptor): Pair<Content, (DocumentationNode) -> Unit> {
- val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
- if (psi is PsiDocCommentOwner) {
- val parseResult = JavadocParser(
- refGraph,
- logger,
- signatureProvider,
- externalDocumentationLinkResolver
- ).parseDocumentation(psi as PsiNamedElement)
- return parseResult.content to { node -> }
- }
- return Content.Empty to { node -> }
- }
-
- fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, KDocTag::class.java) ?: arrayOf()
-
- private fun MutableContent.addTagToSeeAlso(descriptor: DeclarationDescriptor, seeTag: KDocTag) {
- val subjectName = seeTag.getSubjectName()
- if (subjectName != null) {
- val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null)
- val link = linkResolver.resolveContentLink(descriptor, subjectName)
- link.append(ContentText(subjectName))
- val para = ContentParagraph()
- para.append(link)
- seeSection.append(para)
- }
- }
-
-}
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
deleted file mode 100644
index 6d258564..00000000
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ /dev/null
@@ -1,534 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.psi.PsiJavaFile
-import org.jetbrains.dokka.DokkaConfiguration.PassConfiguration
-import org.jetbrains.kotlin.builtins.KotlinBuiltIns
-import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.idea.kdoc.findKDoc
-import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.descriptorUtil.*
-import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
-import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
-import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
-import org.jetbrains.kotlin.resolve.source.PsiSourceElement
-import org.jetbrains.kotlin.types.*
-import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
-import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
-import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
-import org.jetbrains.kotlin.types.typeUtil.supertypes
-import org.jetbrains.kotlin.util.supertypesWithAny
-import kotlin.reflect.KClass
-import com.google.inject.name.Named as GuiceNamed
-
-private fun isExtensionForExternalClass(
- extensionFunctionDescriptor: DeclarationDescriptor,
- extensionReceiverDescriptor: DeclarationDescriptor,
- allFqNames: Collection<FqName>
-): Boolean {
- val extensionFunctionPackage =
- DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java)
- val extensionReceiverPackage =
- DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java)
- return extensionFunctionPackage != null && extensionReceiverPackage != null &&
- extensionFunctionPackage.fqName != extensionReceiverPackage.fqName &&
- extensionReceiverPackage.fqName !in allFqNames
-}
-
-interface PackageDocumentationBuilder {
- fun buildPackageDocumentation(
- documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNodes.Package,
- declarations: List<DeclarationDescriptor>,
- allFqNames: Collection<FqName>
- )
-}
-
-interface DefaultPlatformsProvider {
- fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String>
-}
-
-val ignoredSupertypes = setOf(
- "kotlin.Annotation", "kotlin.Enum", "kotlin.Any"
-)
-
-class DocumentationBuilder
-@Inject constructor(
- val resolutionFacade: DokkaResolutionFacade,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- val logger: DokkaLogger
-) {
-
- private fun DocumentationNodes.Class.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) {
- val unwrappedType = superType.unwrap()
- if (unwrappedType is AbbreviatedType) {
- appendSupertype(descriptor, unwrappedType.abbreviation, backref)
- } else {
- appendType(unwrappedType, descriptor)
- }
- }
-
- private fun DocumentationNodes.Class.appendType(
- kotlinType: KotlinType?,
- descriptor: ClassDescriptor?
- ) {
- if (kotlinType == null)
- return
- (kotlinType.unwrap() as? AbbreviatedType)?.let {
- return appendType(it.abbreviation, descriptor)
- }
-
- if (kotlinType.isDynamic()) {
- append(kind.createNode("dynamic", descriptor), RefKind.Detail)
- return
- }
-
- val classifierDescriptor = kotlinType.constructor.declarationDescriptor
- val name = when (classifierDescriptor) {
- is ClassDescriptor -> {
- if (classifierDescriptor.isCompanionObject) {
- classifierDescriptor.containingDeclaration.name.asString() +
- "." + classifierDescriptor.name.asString()
- } else {
- classifierDescriptor.name.asString()
- }
- }
- is Named -> classifierDescriptor.name.asString()
- else -> "<anonymous>"
- }
- val node = kind.createNode(name, descriptor)
-
- append(node, RefKind.Detail)
- for (typeArgument in kotlinType.arguments) {
- node.appendProjection(typeArgument, null)
- }
- }
-
- fun DocumentationNode<*>.appendChild(descriptor: DeclarationDescriptor) {
- if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) {
- val node = descriptor.build()
- append(node, kind)
- }
- }
-
- fun DocumentationNode.appendMember(descriptor: DeclarationDescriptor) {
- if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) {
- val existingNode = members.firstOrNull { it.descriptor?.fqNameSafe == descriptor.fqNameSafe }
- if (existingNode != null) {
- if (descriptor is ClassDescriptor) {
- val membersToDocument = descriptor.collectMembersToDocument()
- for ((memberDescriptor, _, _) in membersToDocument) {
- if (memberDescriptor is ClassDescriptor) {
- existingNode.appendMember(memberDescriptor) // recurse into nested classes
- } else {
- if (members.any { it.descriptor?.fqNameSafe == memberDescriptor.fqNameSafe }) {
- existingNode.appendClassMember(memberDescriptor)
- }
- }
- }
- }
- } else {
- appendChild(descriptor, RefKind.Member)
- }
- }
- }
-
- private fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor) {
- if (descriptor !is CallableMemberDescriptor || descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
- appendChild(descriptorToUse, RefKind.Member)
- }
- }
-
- fun DocumentationNodes.Module.appendFragments(
- fragments: Collection<PackageFragmentDescriptor>,
- packageDocumentationBuilder: PackageDocumentationBuilder
- ) {
- val allFqNames = fragments.filter { it.isDocumented(passConfiguration) }.map { it.fqName }.distinct()
-
- for (packageName in allFqNames) {
- if (packageName.isRoot && !passConfiguration.includeRootPackage) continue
- val declarations = fragments.filter { it.fqName == packageName }
- .flatMap { it.getMemberScope().getContributedDescriptors() }
-
- if (passConfiguration.skipEmptyPackages && declarations.none { it.isDocumented(passConfiguration) }) continue
- logger.info(" package $packageName: ${declarations.count()} declarations")
- val packageNode = findOrCreatePackageNode(this, packageName.asString())
- packageDocumentationBuilder.buildPackageDocumentation(
- this@DocumentationBuilder, packageName, packageNode,
- declarations, allFqNames
- )
- }
- }
-
- fun findOrCreatePackageNode(
- module: DocumentationNodes.Module,
- packageName: String
- ): DocumentationNode<*> {
- val node = module?.member(DocumentationNodes.Package::class) ?: DocumentationNodes.Package(packageName)
- if (module != null && node !in module.members) {
- module.append(node, RefKind.Member)
- }
- return node
- }
-
- fun propagateExtensionFunctionsToSubclasses(
- fragments: Collection<PackageFragmentDescriptor>,
- resolutionFacade: DokkaResolutionFacade
- ) {
-
- val moduleDescriptor = resolutionFacade.moduleDescriptor
-
- // Wide-collect all view descriptors
- val allPackageViewDescriptors = generateSequence(listOf(moduleDescriptor.getPackage(FqName.ROOT))) { packages ->
- packages
- .flatMap { pkg ->
- moduleDescriptor.getSubPackagesOf(pkg.fqName) { true }
- }.map { fqName ->
- moduleDescriptor.getPackage(fqName)
- }.takeUnless { it.isEmpty() }
- }.flatten()
-
- val allDescriptors =
- if (passConfiguration.collectInheritedExtensionsFromLibraries) {
- allPackageViewDescriptors.map { it.memberScope }
- } else {
- fragments.asSequence().map { it.getMemberScope() }
- }.flatMap {
- it.getDescriptorsFiltered(
- DescriptorKindFilter.CALLABLES
- ).asSequence()
- }
-
- val allExtensionFunctions =
- allDescriptors
- .filterIsInstance<CallableMemberDescriptor>()
- .filter { it.extensionReceiverParameter != null }
- val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name }
-
- fun isIgnoredReceiverType(type: KotlinType) =
- type.isDynamic() ||
- type.isAnyOrNullableAny() ||
- (type.isTypeParameter() && type.immediateSupertypes().all { it.isAnyOrNullableAny() })
-
-
- for (extensionFunction in allExtensionFunctions) {
- val extensionReceiverParameter = extensionFunction.extensionReceiverParameter!!
- if (extensionFunction.dispatchReceiverParameter != null) continue
- val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name]
- ?.filter { fn -> fn.canShadow(extensionFunction) }
- ?: emptyList()
-
- if (isIgnoredReceiverType(extensionReceiverParameter.type)) continue
- }
- }
-
- private fun CallableMemberDescriptor.canShadow(other: CallableMemberDescriptor): Boolean {
- if (this == other) return false
- if (this is PropertyDescriptor && other is PropertyDescriptor) {
- return true
- }
- if (this is FunctionDescriptor && other is FunctionDescriptor) {
- val parameters1 = valueParameters
- val parameters2 = other.valueParameters
- if (parameters1.size != parameters2.size) {
- return false
- }
- for ((p1, p2) in parameters1 zip parameters2) {
- if (p1.type != p2.type) {
- return false
- }
- }
- return true
- }
- return false
- }
-
- fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
- is ClassifierDescriptor -> build()
- is ConstructorDescriptor -> build()
- is PropertyDescriptor -> build()
- is FunctionDescriptor -> build()
- is ValueParameterDescriptor -> build()
- is ReceiverParameterDescriptor -> build()
- else -> throw IllegalStateException("Descriptor $this is not known")
- }
-
- fun ClassifierDescriptor.build(external: Boolean = false): DocumentationNode = when (this) {
- is ClassDescriptor -> build(this, external)
- is TypeAliasDescriptor -> build()
- is TypeParameterDescriptor -> build()
- else -> throw IllegalStateException("Descriptor $this is not known")
- }
-
- fun TypeAliasDescriptor.build(): DocumentationNode {
- val node = DocumentationNodes.TypeAlias(name.asString(), this)
- node.appendType(underlyingType, this, DocumentationNodes.TypeAliasUnderlyingType::class)
- return node
- }
-
- fun ClassDescriptor.build(descriptor: DeclarationDescriptor, external: Boolean = false): DocumentationNode {
- val node = when {
- kind == ClassKind.OBJECT -> DocumentationNodes.Object(descriptor.name.asString(), descriptor)
- kind == ClassKind.INTERFACE -> DocumentationNodes.Interface(descriptor.name.asString(), descriptor)
- kind == ClassKind.ENUM_CLASS -> DocumentationNodes.Enum(descriptor.name.asString(), descriptor)
- kind == ClassKind.ANNOTATION_CLASS -> DocumentationNodes.AnnotationClass(descriptor.name.asString(), descriptor)
- kind == ClassKind.ENUM_ENTRY -> DocumentationNodes.EnumItem(descriptor.name.asString(), descriptor)
- isSubclassOfThrowable() -> DocumentationNodes.Exception(descriptor.name.asString(), descriptor)
- else -> DocumentationNodes.Class(descriptor.name.asString(), descriptor)
- }
- supertypesWithAnyPrecise().forEach {
- node.appendSupertype(this, it, !external)
- }
- if (!external) {
- for ((membersDescriptor, _, _) in collectMembersToDocument()) {
- node.appendClassMember(membersDescriptor)
- }
- }
- return node
- }
-
- data class ClassMember(
- val descriptor: DeclarationDescriptor,
- val inheritedLinkKind: RefKind = RefKind.InheritedMember,
- val extraModifier: String? = null
- )
-
- private fun ClassDescriptor.collectMembersToDocument(): List<ClassMember> {
- val result = arrayListOf<ClassMember>()
- if (kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) {
- val constructorsToDocument = if (kind == ClassKind.ENUM_CLASS)
- constructors.filter { it.valueParameters.size > 0 }
- else
- constructors
- constructorsToDocument.mapTo(result) { ClassMember(it) }
- }
-
- defaultType.memberScope.getContributedDescriptors()
- .filter { it != companionObjectDescriptor }
- .mapTo(result) { ClassMember(it) }
-
- staticScope.getContributedDescriptors()
- .mapTo(result) { ClassMember(it, extraModifier = "static") }
-
- val companionObjectDescriptor = companionObjectDescriptor
- if (companionObjectDescriptor != null && companionObjectDescriptor.isDocumented(passConfiguration)) {
- val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()
- val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() }
- descriptorsToDocument.mapTo(result) {
- ClassMember(it, inheritedLinkKind = RefKind.InheritedCompanionObjectMember)
- }
-
- if (companionObjectDescriptor.getAllSuperclassesWithoutAny().isNotEmpty()
- || companionObjectDescriptor.getSuperInterfaces().isNotEmpty()) {
- result += ClassMember(companionObjectDescriptor)
- }
- }
- return result
- }
-
- private fun CallableDescriptor.isInheritedFromAny(): Boolean {
- return findTopMostOverriddenDescriptors().any {
- DescriptorUtils.getFqNameSafe(it.containingDeclaration).asString() == "kotlin.Any"
- }
- }
-
- private fun ClassDescriptor.isSubclassOfThrowable(): Boolean =
- defaultType.supertypes().any { it.constructor.declarationDescriptor == builtIns.throwable }
-
- fun ConstructorDescriptor.build(): DocumentationNode =
- DocumentationNodes.Constructor(name.asString(), this)
-
- private fun CallableMemberDescriptor.inCompanionObject(): Boolean {
- val containingDeclaration = containingDeclaration
- if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject == true) {
- return true
- }
- val receiver = extensionReceiverParameter
- return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false
- }
-
- fun FunctionDescriptor.build(): DocumentationNode =
- if (inCompanionObject())
- DocumentationNodes.CompanionObjectFunction(name.asString(),this)
- else
- DocumentationNodes.Function(name.asString(),this)
-
- fun PropertyDescriptor.build(): DocumentationNode =
- DocumentationNodes.Property(name.asString(), this)
-
- fun ValueParameterDescriptor.build(): DocumentationNode =
- DocumentationNodes.Parameter(name.asString(), this)
-
- fun TypeParameterDescriptor.build(): DocumentationNode =
- DocumentationNodes.TypeParameter(name.asString(), this)
-
- fun ReceiverParameterDescriptor.build(): DocumentationNode =
- DocumentationNodes.Receiver(name.asString(), this)
-}
-
-fun DeclarationDescriptor.isDocumented(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean {
- return (passConfiguration.effectivePackageOptions(fqNameSafe).includeNonPublic
- || this !is MemberDescriptor
- || this.visibility.isPublicAPI)
- && !isDocumentationSuppressed(passConfiguration)
- && (!passConfiguration.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
-}
-
-private fun DeclarationDescriptor.isGenerated() =
- this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION
-
-class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
-
- override fun buildPackageDocumentation(
- documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>,
- allFqNames: Collection<FqName>
- ) {
- declarations.forEach { descriptor ->
- with(documentationBuilder) {
- if (descriptor.isDocumented(passConfiguration)) {
- packageNode.appendMember(descriptor)
- }
- }
- }
- }
-}
-
-class KotlinJavaDocumentationBuilder
-@Inject constructor(
- val resolutionFacade: DokkaResolutionFacade,
- val documentationBuilder: DocumentationBuilder,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- val logger: DokkaLogger
-) : JavaDocumentationBuilder {
- override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
- val classDescriptors = file.classes.map {
- it.getJavaClassDescriptor(resolutionFacade)
- }
-
- if (classDescriptors.any { it != null && it.isDocumented(passConfiguration) }) {
- val packageNode = documentationBuilder.findOrCreatePackageNode(module, file.packageName)
-
- for (descriptor in classDescriptors.filterNotNull()) {
- with(documentationBuilder) {
- packageNode.appendChild(descriptor, RefKind.Member)
- }
- }
- }
- }
-}
-
-fun DeclarationDescriptor.isDocumentationSuppressed(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean {
-
- if (passConfiguration.effectivePackageOptions(fqNameSafe).suppress) return true
-
- val path = this.findPsi()?.containingFile?.virtualFile?.path
- if (path != null) {
- if (path in passConfiguration.suppressedFiles) return true
- }
-
- val doc = findKDoc()
- if (doc is KDocSection && doc.findTagByName("suppress") != null) return true
-
- return hasSuppressDocTag(sourcePsi())
-}
-
-fun DeclarationDescriptor.sourcePsi() =
- ((original as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
-
-fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any {
- DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated"
-} || (this is ConstructorDescriptor && containingDeclaration.isDeprecated())
-
-fun DeclarationDescriptor.signature(): String {
- if (this != original) return original.signature()
- return when (this) {
- is ClassDescriptor,
- is PackageFragmentDescriptor,
- is PackageViewDescriptor,
- is TypeAliasDescriptor -> DescriptorUtils.getFqName(this).asString()
-
- is PropertyDescriptor -> containingDeclaration.signature() + "$" + name + receiverSignature()
- is FunctionDescriptor -> containingDeclaration.signature() + "$" + name + parameterSignature()
- is ValueParameterDescriptor -> containingDeclaration.signature() + "/" + name
- is TypeParameterDescriptor -> containingDeclaration.signature() + "*" + name
- is ReceiverParameterDescriptor -> containingDeclaration.signature() + "/" + name
- else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
- }
-}
-
-fun PropertyDescriptor.receiverSignature(): String {
- val receiver = extensionReceiverParameter
- if (receiver != null) {
- return "#" + receiver.type.signature()
- }
- return ""
-}
-
-fun CallableMemberDescriptor.parameterSignature(): String {
- val params = valueParameters.map { it.type }.toMutableList()
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- params.add(0, extensionReceiver.type)
- }
- return params.joinToString(prefix = "(", postfix = ")") { it.signature() }
-}
-
-fun KotlinType.signature(): String {
- val visited = hashSetOf<KotlinType>()
-
- fun KotlinType.signatureRecursive(): String {
- if (this in visited) {
- return ""
- }
- visited.add(this)
-
- val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>"
- val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString()
- if (arguments.isEmpty()) {
- return typeName
- }
- return typeName + arguments.joinToString(prefix = "((", postfix = "))") { it.type.signatureRecursive() }
- }
-
- return signatureRecursive()
-}
-
-fun DeclarationDescriptor.signatureWithSourceLocation(): String {
- val signature = signature()
- val sourceLocation = sourceLocation()
- return if (sourceLocation != null) "$signature ($sourceLocation)" else signature
-}
-
-fun DeclarationDescriptor.sourceLocation(): String? {
- val psi = sourcePsi()
- if (psi != null) {
- val fileName = psi.containingFile.name
- val lineNumber = psi.lineNumber()
- return if (lineNumber != null) "$fileName:$lineNumber" else fileName
- }
- return null
-}
-
-fun ClassDescriptor.supertypesWithAnyPrecise(): Collection<KotlinType> {
- if (KotlinBuiltIns.isAny(this)) {
- return emptyList()
- }
- return typeConstructor.supertypesWithAny()
-}
-
-fun PassConfiguration.effectivePackageOptions(pack: String): DokkaConfiguration.PackageOptions {
- val rootPackageOptions = PackageOptionsImpl("", includeNonPublic, reportUndocumented, skipDeprecated, false)
- return perPackageOptions.firstOrNull { pack == it.prefix || pack.startsWith(it.prefix + ".") } ?: rootPackageOptions
-}
-
-fun PassConfiguration.effectivePackageOptions(pack: FqName): DokkaConfiguration.PackageOptions =
- effectivePackageOptions(pack.asString())
-
diff --git a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
deleted file mode 100644
index c7187b23..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiMember
-import com.intellij.psi.PsiPackage
-import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
-import org.jetbrains.kotlin.asJava.elements.KtLightElement
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.resolve.BindingContext
-import javax.inject.Inject
-
-class KotlinElementSignatureProvider @Inject constructor(
- val resolutionFacade: DokkaResolutionFacade
-) : ElementSignatureProvider {
- override fun signature(forPsi: PsiElement): String {
- return forPsi.extractDescriptor(resolutionFacade)
- ?.let { signature(it) }
- ?: run { "no desc for $forPsi in ${(forPsi as? PsiMember)?.containingClass}" }
- }
-
- override fun signature(forDesc: DeclarationDescriptor): String = forDesc.signature()
-}
-
-
-fun PsiElement.extractDescriptor(resolutionFacade: DokkaResolutionFacade): DeclarationDescriptor? =
- when (val forPsi = this) {
- is KtLightClassForFacade -> resolutionFacade.moduleDescriptor.getPackage(forPsi.fqName)
- is KtLightElement<*, *> -> (forPsi.kotlinOrigin!!).extractDescriptor(resolutionFacade)
- is PsiPackage -> resolutionFacade.moduleDescriptor.getPackage(FqName(forPsi.qualifiedName))
- is PsiMember -> forPsi.getJavaOrKotlinMemberDescriptor(resolutionFacade)
- else -> resolutionFacade.resolveSession.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, forPsi]
- }
diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
deleted file mode 100644
index 7310610f..00000000
--- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt
+++ /dev/null
@@ -1,473 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-
-/**
- * Implements [LanguageService] and provides rendering of symbols in Kotlin language
- */
-class KotlinLanguageService : CommonLanguageService() {
- override fun showModifierInSummary(node: DocumentationNode): Boolean {
- return node.name !in fullOnlyModifiers
- }
-
- private val fullOnlyModifiers =
- setOf("public", "protected", "private", "internal", "inline", "noinline", "crossinline", "reified")
-
- override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
- return content {
- when (node.kind) {
- NodeKind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node)
- in NodeKind.classLike -> renderClass(node, renderMode)
-
- NodeKind.EnumItem,
- NodeKind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name)
-
- NodeKind.Parameter -> renderParameter(node, renderMode)
- NodeKind.TypeParameter -> renderTypeParameter(node, renderMode)
- NodeKind.Type,
- NodeKind.UpperBound -> renderType(node, renderMode)
-
- NodeKind.Modifier -> renderModifier(this, node, renderMode)
- NodeKind.Constructor,
- NodeKind.Function,
- NodeKind.CompanionObjectFunction -> renderFunction(node, renderMode)
- NodeKind.Property,
- NodeKind.CompanionObjectProperty -> renderProperty(node, renderMode)
- else -> identifier(node.name)
- }
- }
- }
-
-
- override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? {
- if (nodes.size < 2) return null
- val receiverKind = nodes.getReceiverKind() ?: return null
- val functionWithTypeParameter = nodes.firstOrNull { it.details(NodeKind.TypeParameter).any() } ?: return null
- return content {
- val typeParameter = functionWithTypeParameter.details(NodeKind.TypeParameter).first()
- if (functionWithTypeParameter.kind == NodeKind.Function) {
- renderFunction(
- functionWithTypeParameter,
- RenderMode.SUMMARY,
- SummarizingMapper(receiverKind, typeParameter.name)
- )
- } else {
- renderProperty(
- functionWithTypeParameter,
- RenderMode.SUMMARY,
- SummarizingMapper(receiverKind, typeParameter.name)
- )
- }
- }
- }
-
- private fun List<DocumentationNode>.getReceiverKind(): ReceiverKind? {
- val qNames = mapNotNull { it.getReceiverQName() }
- if (qNames.size != size)
- return null
-
- return ReceiverKind.values().firstOrNull { kind -> qNames.all { it in kind.classes } }
- }
-
- private fun DocumentationNode.getReceiverQName(): String? {
- if (kind != NodeKind.Function && kind != NodeKind.Property) return null
- val receiver = details(NodeKind.Receiver).singleOrNull() ?: return null
- return receiver.detail(NodeKind.Type).qualifiedNameFromType()
- }
-
- companion object {
- private val arrayClasses = setOf(
- "kotlin.Array",
- "kotlin.BooleanArray",
- "kotlin.ByteArray",
- "kotlin.CharArray",
- "kotlin.ShortArray",
- "kotlin.IntArray",
- "kotlin.LongArray",
- "kotlin.FloatArray",
- "kotlin.DoubleArray"
- )
-
- private val arrayOrListClasses = setOf("kotlin.List") + arrayClasses
-
- private val iterableClasses = setOf(
- "kotlin.Collection",
- "kotlin.Sequence",
- "kotlin.Iterable",
- "kotlin.Map",
- "kotlin.String",
- "kotlin.CharSequence"
- ) + arrayOrListClasses
- }
-
- private enum class ReceiverKind(val receiverName: String, val classes: Collection<String>) {
- ARRAY("any_array", arrayClasses),
- ARRAY_OR_LIST("any_array_or_list", arrayOrListClasses),
- ITERABLE("any_iterable", iterableClasses),
- }
-
- interface SignatureMapper {
- fun renderReceiver(receiver: DocumentationNode, to: ContentBlock)
- }
-
- private class SummarizingMapper(val kind: ReceiverKind, val typeParameterName: String) : SignatureMapper {
- override fun renderReceiver(receiver: DocumentationNode, to: ContentBlock) {
- to.append(ContentIdentifier(kind.receiverName, IdentifierKind.SummarizedTypeName))
- to.text("<$typeParameterName>")
- }
- }
-
- private fun ContentBlock.renderFunctionalTypeParameterName(node: DocumentationNode, renderMode: RenderMode) {
- node.references(RefKind.HiddenAnnotation).map { it.to }
- .find { it.name == "ParameterName" }?.let {
- val parameterNameValue = it.detail(NodeKind.Parameter).detail(NodeKind.Value)
- identifier(parameterNameValue.name.removeSurrounding("\""), IdentifierKind.ParameterName)
- symbol(":")
- nbsp()
- }
- }
-
- private fun ContentBlock.renderFunctionalType(node: DocumentationNode, renderMode: RenderMode) {
- var typeArguments = node.details(NodeKind.Type)
-
- if (node.name.startsWith("Suspend")) {
- keyword("suspend ")
- }
-
- // lambda
- val isExtension = node.annotations.any { it.name == "ExtensionFunctionType" }
- if (isExtension) {
- renderType(typeArguments.first(), renderMode)
- symbol(".")
- typeArguments = typeArguments.drop(1)
- }
- symbol("(")
- renderList(typeArguments.take(typeArguments.size - 1), noWrap = true) {
- renderFunctionalTypeParameterName(it, renderMode)
- renderType(it, renderMode)
- }
- symbol(")")
- nbsp()
- symbol("->")
- nbsp()
- renderType(typeArguments.last(), renderMode)
-
- }
-
- private fun DocumentationNode.isFunctionalType(): Boolean {
- val typeArguments = details(NodeKind.Type)
- val functionalTypeName = "Function${typeArguments.count() - 1}"
- val suspendFunctionalTypeName = "Suspend$functionalTypeName"
- return name == functionalTypeName || name == suspendFunctionalTypeName
- }
-
- private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) {
- if (node.name == "dynamic") {
- keyword("dynamic")
- return
- }
-
- val nullabilityModifier = node.detailOrNull(NodeKind.NullabilityModifier)
-
- if (node.isFunctionalType()) {
- if (nullabilityModifier != null) {
- symbol("(")
- renderFunctionalType(node, renderMode)
- symbol(")")
- symbol(nullabilityModifier.name)
- } else {
- renderFunctionalType(node, renderMode)
- }
- return
- }
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode, true)
- renderLinked(this, node) {
- identifier(it.typeDeclarationClass?.classNodeNameWithOuterClass() ?: it.name, IdentifierKind.TypeName)
- }
- val typeArguments = node.details(NodeKind.Type)
- if (typeArguments.isNotEmpty()) {
- symbol("<")
- renderList(typeArguments, noWrap = true) {
- renderType(it, renderMode)
- }
- symbol(">")
- }
-
- nullabilityModifier ?.apply {
- symbol(nullabilityModifier.name)
- }
- }
-
- override fun renderModifier(
- block: ContentBlock,
- node: DocumentationNode,
- renderMode: RenderMode,
- nowrap: Boolean
- ) {
- when (node.name) {
- "final", "public", "var", "expect", "actual", "external" -> {
- }
- else -> {
- if (showModifierInSummary(node) || renderMode == RenderMode.FULL) {
- super.renderModifier(block, node, renderMode, nowrap)
- }
- }
- }
- }
-
- private fun ContentBlock.renderTypeParameter(node: DocumentationNode, renderMode: RenderMode) {
- renderModifiersForNode(node, renderMode, true)
-
- identifier(node.name)
-
- val constraints = node.details(NodeKind.UpperBound)
- if (constraints.size == 1) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(constraints, noWrap = true) {
- renderType(it, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- identifier(node.name, IdentifierKind.ParameterName, node.detailOrNull(NodeKind.Signature)?.name)
- symbol(":")
- nbsp()
- val parameterType = node.detail(NodeKind.Type)
- renderType(parameterType, renderMode)
- val valueNode = node.details(NodeKind.Value).firstOrNull()
- if (valueNode != null) {
- nbsp()
- symbol("=")
- nbsp()
- text(valueNode.name)
- }
- }
-
- private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode, renderMode: RenderMode) {
- val typeParameters = node.details(NodeKind.TypeParameter)
- if (typeParameters.any()) {
- symbol("<")
- renderList(typeParameters) {
- renderTypeParameter(it, renderMode)
- }
- symbol(">")
- }
- }
-
- private fun ContentBlock.renderExtraTypeParameterConstraints(node: DocumentationNode, renderMode: RenderMode) {
- val parametersWithMultipleConstraints =
- node.details(NodeKind.TypeParameter).filter { it.details(NodeKind.UpperBound).size > 1 }
- val parametersWithConstraints = parametersWithMultipleConstraints
- .flatMap { parameter ->
- parameter.details(NodeKind.UpperBound).map { constraint -> parameter to constraint }
- }
- if (parametersWithMultipleConstraints.isNotEmpty()) {
- keyword(" where ")
- renderList(parametersWithConstraints) {
- identifier(it.first.name)
- nbsp()
- symbol(":")
- nbsp()
- renderType(it.second, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) {
- val supertypes = node.details(NodeKind.Supertype).filterNot { it.qualifiedNameFromType() in ignoredSupertypes }
- if (supertypes.any()) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(supertypes) {
- indentedSoftLineBreak()
- renderType(it, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderAnnotationsForNode(node: DocumentationNode) {
- node.annotations.forEach {
- renderAnnotation(it)
- }
- }
-
- private fun ContentBlock.renderAnnotation(node: DocumentationNode) {
- identifier("@" + node.name, IdentifierKind.AnnotationName)
- val parameters = node.details(NodeKind.Parameter)
- if (!parameters.isEmpty()) {
- symbol("(")
- renderList(parameters) {
- text(it.detail(NodeKind.Value).name)
- }
- symbol(")")
- }
- text(" ")
- }
-
- private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- NodeKind.Class,
- NodeKind.AnnotationClass,
- NodeKind.Exception,
- NodeKind.Enum -> keyword("class ")
- NodeKind.Interface -> keyword("interface ")
- NodeKind.EnumItem -> keyword("enum val ")
- NodeKind.Object -> keyword("object ")
- NodeKind.TypeAlias -> keyword("typealias ")
- else -> throw IllegalArgumentException("Node $node is not a class-like object")
- }
-
- identifierOrDeprecated(node)
- renderTypeParametersForNode(node, renderMode)
- renderSupertypesForNode(node, renderMode)
- renderExtraTypeParameterConstraints(node, renderMode)
-
- if (node.kind == NodeKind.TypeAlias) {
- nbsp()
- symbol("=")
- nbsp()
- renderType(node.detail(NodeKind.TypeAliasUnderlyingType), renderMode)
- }
- }
-
- private fun ContentBlock.renderFunction(
- node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null
- ) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- NodeKind.Constructor -> identifier(node.owner!!.name)
- NodeKind.Function,
- NodeKind.CompanionObjectFunction -> keyword("fun ")
- else -> throw IllegalArgumentException("Node $node is not a function-like object")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(NodeKind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- if (node.kind != NodeKind.Constructor)
- identifierOrDeprecated(node)
-
- symbol("(")
- val parameters = node.details(NodeKind.Parameter)
- renderList(parameters) {
- indentedSoftLineBreak()
- renderParameter(it, renderMode)
- }
- if (needReturnType(node)) {
- if (parameters.isNotEmpty()) {
- softLineBreak()
- }
- symbol(")")
- symbol(": ")
- renderType(node.detail(NodeKind.Type), renderMode)
- } else {
- symbol(")")
- }
- renderExtraTypeParameterConstraints(node, renderMode)
- }
-
- private fun ContentBlock.renderReceiver(
- node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper?
- ) {
- val receiver = node.details(NodeKind.Receiver).singleOrNull()
- if (receiver != null) {
- if (signatureMapper != null) {
- signatureMapper.renderReceiver(receiver, this)
- } else {
- val type = receiver.detail(NodeKind.Type)
-
- if (type.isFunctionalType()) {
- symbol("(")
- renderFunctionalType(type, renderMode)
- symbol(")")
- } else {
- renderType(type, renderMode)
- }
- }
- symbol(".")
- }
- }
-
- private fun needReturnType(node: DocumentationNode) = when (node.kind) {
- NodeKind.Constructor -> false
- else -> !node.isUnitReturnType()
- }
-
- fun DocumentationNode.isUnitReturnType(): Boolean =
- detail(NodeKind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit"
-
- private fun ContentBlock.renderProperty(
- node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null
- ) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- NodeKind.Property,
- NodeKind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ")
- else -> throw IllegalArgumentException("Node $node is not a property")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(NodeKind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- identifierOrDeprecated(node)
- symbol(": ")
- renderType(node.detail(NodeKind.Type), renderMode)
- renderExtraTypeParameterConstraints(node, renderMode)
- }
-
- fun DocumentationNode.getPropertyKeyword() =
- if (details(NodeKind.Modifier).any { it.name == "var" }) "var" else "val"
-
- fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) {
- if (node.deprecation != null) {
- val strike = ContentStrikethrough()
- strike.identifier(node.name)
- append(strike)
- } else {
- identifier(node.name)
- }
- }
-}
-
-fun DocumentationNode.qualifiedNameFromType(): String {
- return details.firstOrNull { it.kind == NodeKind.QualifiedName }?.name
- ?: (links.firstOrNull() ?: hiddenLinks.firstOrNull())?.qualifiedName()
- ?: name
-}
-
-
-val DocumentationNode.typeDeclarationClass
- get() = (links.firstOrNull { it.kind in NodeKind.classLike } ?: externalType)
diff --git a/core/src/main/kotlin/Languages/CommonLanguageService.kt b/core/src/main/kotlin/Languages/CommonLanguageService.kt
deleted file mode 100644
index ddc95d32..00000000
--- a/core/src/main/kotlin/Languages/CommonLanguageService.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.jetbrains.dokka
-
-
-abstract class CommonLanguageService : LanguageService {
-
- protected fun ContentBlock.renderPackage(node: DocumentationNode) {
- keyword("package")
- nbsp()
- identifier(node.name)
- }
-
- override fun renderName(node: DocumentationNode): String {
- return when (node.kind) {
- NodeKind.Constructor -> node.owner!!.name
- else -> node.name
- }
- }
-
- open fun renderModifier(
- block: ContentBlock,
- node: DocumentationNode,
- renderMode: LanguageService.RenderMode,
- nowrap: Boolean = false
- ) = with(block) {
- keyword(node.name)
- if (nowrap) {
- nbsp()
- } else {
- text(" ")
- }
- }
-
- protected fun renderLinked(
- block: ContentBlock,
- node: DocumentationNode,
- body: ContentBlock.(DocumentationNode) -> Unit
- ) = with(block) {
- val to = node.links.firstOrNull()
- if (to == null)
- body(node)
- else
- link(to) {
- this.body(node)
- }
- }
-
- protected fun <T> ContentBlock.renderList(
- nodes: List<T>, separator: String = ", ",
- noWrap: Boolean = false, renderItem: (T) -> Unit
- ) {
- if (nodes.none())
- return
- renderItem(nodes.first())
- nodes.drop(1).forEach {
- if (noWrap) {
- symbol(separator.removeSuffix(" "))
- nbsp()
- } else {
- symbol(separator)
- }
- renderItem(it)
- }
- }
-
- abstract fun showModifierInSummary(node: DocumentationNode): Boolean
-
- protected fun ContentBlock.renderModifiersForNode(
- node: DocumentationNode,
- renderMode: LanguageService.RenderMode,
- nowrap: Boolean = false
- ) {
- val modifiers = node.details(NodeKind.Modifier)
- for (it in modifiers) {
- if (node.kind == NodeKind.Interface && it.name == "abstract")
- continue
- if (renderMode == LanguageService.RenderMode.SUMMARY && !showModifierInSummary(it)) {
- continue
- }
- renderModifier(this, it, renderMode, nowrap)
- }
- }
-
-
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Languages/LanguageService.kt b/core/src/main/kotlin/Languages/LanguageService.kt
deleted file mode 100644
index b0f4bbc9..00000000
--- a/core/src/main/kotlin/Languages/LanguageService.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.jetbrains.dokka
-
-/**
- * Provides facility for rendering [DocumentationNode] as a language-dependent declaration
- */
-interface LanguageService {
- enum class RenderMode {
- /** Brief signature (used in a list of all members of the class). */
- SUMMARY,
- /** Full signature (used in the page describing the member itself */
- FULL
- }
-
- /**
- * Renders a [node] as a class, function, property or other signature in a target language.
- * @param node A [DocumentationNode] to render
- * @return [ContentNode] which is a root for a rich content tree suitable for formatting with [FormatService]
- */
- fun render(node: DocumentationNode, renderMode: RenderMode = RenderMode.FULL): ContentNode
-
- /**
- * Tries to summarize the signatures of the specified documentation nodes in a compact representation.
- * Returns the representation if successful, or null if the signatures could not be summarized.
- */
- fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode?
-
- /**
- * Renders [node] as a named representation in the target language
- *
- * For example:
- * ${code org.jetbrains.dokka.example}
- *
- * $node: A [DocumentationNode] to render
- * $returns: [String] which is a string representation of the node's name
- */
- fun renderName(node: DocumentationNode): String
-}
-
-fun example(service: LanguageService, node: DocumentationNode) {
- println("Node name: ${service.renderName(node)}")
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Model/PackageDocs.kt b/core/src/main/kotlin/Model/PackageDocs.kt
deleted file mode 100644
index b24efc5d..00000000
--- a/core/src/main/kotlin/Model/PackageDocs.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.google.inject.Singleton
-import com.intellij.ide.highlighter.JavaFileType
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiFileFactory
-import com.intellij.psi.util.PsiTreeUtil
-import com.intellij.util.LocalTimeCounter
-import com.intellij.openapi.util.text.StringUtil
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.intellij.markdown.parser.LinkMap
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
-import java.io.File
-
-@Singleton
-class PackageDocs
- @Inject constructor(val linkResolver: DeclarationLinkResolver?,
- val logger: DokkaLogger,
- val environment: KotlinCoreEnvironment,
- val refGraph: NodeReferenceGraph,
- val elementSignatureProvider: ElementSignatureProvider)
-{
- val moduleContent: MutableContent = MutableContent()
- private val _packageContent: MutableMap<String, MutableContent> = hashMapOf()
- val packageContent: Map<String, Content>
- get() = _packageContent
-
- fun parse(fileName: String, linkResolveContext: List<PackageFragmentDescriptor>) {
- val file = File(fileName)
- if (file.exists()) {
- val text = StringUtil.convertLineSeparators(file.readText())
- val tree = parseMarkdown(text)
- val linkMap = LinkMap.buildLinkMap(tree.node, text)
- var targetContent: MutableContent = moduleContent
- tree.children.forEach {
- if (it.type == MarkdownElementTypes.ATX_1) {
- val headingText = it.child(MarkdownTokenTypes.ATX_CONTENT)?.text
- if (headingText != null) {
- targetContent = findTargetContent(headingText.trimStart())
- }
- } else {
- buildContentTo(it, targetContent, LinkResolver(linkMap) { resolveContentLink(fileName, it, linkResolveContext) })
- }
- }
- } else {
- logger.warn("Include file $file was not found.")
- }
- }
-
- private fun parseHtmlAsJavadoc(text: String, packageName: String, file: File) {
- val javadocText = text
- .replace("*/", "*&#47;")
- .removeSurrounding("<html>", "</html>", true).trim()
- .removeSurrounding("<body>", "</body>", true)
- .lineSequence()
- .map { "* $it" }
- .joinToString (separator = "\n", prefix = "/**\n", postfix = "\n*/")
- parseJavadoc(javadocText, packageName, file)
- }
-
- private fun CharSequence.removeSurrounding(prefix: CharSequence, suffix: CharSequence, ignoringCase: Boolean = false): CharSequence {
- if ((length >= prefix.length + suffix.length) && startsWith(prefix, ignoringCase) && endsWith(suffix, ignoringCase)) {
- return subSequence(prefix.length, length - suffix.length)
- }
- return subSequence(0, length)
- }
-
-
- private fun parseJavadoc(text: String, packageName: String, file: File) {
-
- val psiFileFactory = PsiFileFactory.getInstance(environment.project)
- val psiFile = psiFileFactory.createFileFromText(
- file.nameWithoutExtension + ".java",
- JavaFileType.INSTANCE,
- "package $packageName; $text\npublic class C {}",
- LocalTimeCounter.currentTime(),
- false,
- true
- )
-
- val psiClass = PsiTreeUtil.getChildOfType(psiFile, PsiClass::class.java)!!
- val parser = JavadocParser(refGraph, logger, elementSignatureProvider, linkResolver?.externalDocumentationLinkResolver!!)
- findOrCreatePackageContent(packageName).apply {
- val content = parser.parseDocumentation(psiClass).content
- children.addAll(content.children)
- content.sections.forEach {
- addSection(it.tag, it.subjectName).children.addAll(it.children)
- }
- }
- }
-
-
- fun parseJava(fileName: String, packageName: String) {
- val file = File(fileName)
- if (file.exists()) {
- val text = file.readText()
-
- val trimmedText = text.trim()
-
- if (trimmedText.startsWith("/**")) {
- parseJavadoc(text, packageName, file)
- } else if (trimmedText.toLowerCase().startsWith("<html>")) {
- parseHtmlAsJavadoc(trimmedText, packageName, file)
- }
- }
- }
-
- private fun findTargetContent(heading: String): MutableContent {
- if (heading.startsWith("Module") || heading.startsWith("module")) {
- return moduleContent
- }
- if (heading.startsWith("Package") || heading.startsWith("package")) {
- return findOrCreatePackageContent(heading.substring("package".length).trim())
- }
- return findOrCreatePackageContent(heading)
- }
-
- private fun findOrCreatePackageContent(packageName: String) =
- _packageContent.getOrPut(packageName) { MutableContent() }
-
- private fun resolveContentLink(fileName: String, href: String, linkResolveContext: List<PackageFragmentDescriptor>): ContentBlock {
- if (linkResolver != null) {
- linkResolveContext
- .asSequence()
- .map { p -> linkResolver.tryResolveContentLink(p, href) }
- .filterNotNull()
- .firstOrNull()
- ?.let { return it }
- }
- logger.warn("Unresolved link to `$href` in include ($fileName)")
- return ContentExternalLink("#")
- }
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/Utilities/DokkaModules.kt b/core/src/main/kotlin/Utilities/DokkaModules.kt
deleted file mode 100644
index 94fc5c62..00000000
--- a/core/src/main/kotlin/Utilities/DokkaModules.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.jetbrains.dokka.Utilities
-
-import com.google.inject.Binder
-import com.google.inject.Module
-import com.google.inject.TypeLiteral
-import com.google.inject.binder.AnnotatedBindingBuilder
-import com.google.inject.name.Names
-import org.jetbrains.dokka.*
-import org.jetbrains.dokka.Formats.FormatDescriptor
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
-import java.io.File
-import kotlin.reflect.KClass
-
-const val impliedPlatformsName = "impliedPlatforms"
-
-class DokkaRunModule(val configuration: DokkaConfiguration) : Module {
- override fun configure(binder: Binder) {
- binder.bind<DokkaConfiguration>().toInstance(configuration)
- binder.bind(StringListType).annotatedWith(Names.named(impliedPlatformsName)).toInstance(configuration.impliedPlatforms)
-
- binder.bind(File::class.java).annotatedWith(Names.named("outputDir")).toInstance(File(configuration.outputDir))
- }
-
-}
-
-class DokkaAnalysisModule(val environment: AnalysisEnvironment,
- val configuration: DokkaConfiguration,
- val defaultPlatformsProvider: DefaultPlatformsProvider,
- val passConfiguration: DokkaConfiguration.PassConfiguration,
- val logger: DokkaLogger) : Module {
- override fun configure(binder: Binder) {
- binder.bind<DokkaLogger>().toInstance(logger)
-
- val coreEnvironment = environment.createCoreEnvironment()
- binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
-
- val (dokkaResolutionFacade, libraryResolutionFacade) = environment.createResolutionFacade(coreEnvironment)
- binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
- binder.bind<DokkaResolutionFacade>().annotatedWith(Names.named("libraryResolutionFacade")).toInstance(libraryResolutionFacade)
-
- binder.bind<DokkaConfiguration.PassConfiguration>().toInstance(passConfiguration)
-
- binder.bind<DefaultPlatformsProvider>().toInstance(defaultPlatformsProvider)
-
- val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", configuration.format)
- descriptor.configureAnalysis(binder)
- }
-}
-
-object StringListType : TypeLiteral<@JvmSuppressWildcards List<String>>()
-
-class DokkaOutputModule(val configuration: DokkaConfiguration,
- val logger: DokkaLogger) : Module {
- override fun configure(binder: Binder) {
- binder.bind<DokkaLogger>().toInstance(logger)
-
- val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", configuration.format)
-
- descriptor.configureOutput(binder)
- }
-}
-
-private inline fun <reified T: Any> Binder.registerCategory(category: String) {
- ServiceLocator.allServices(category).forEach {
- @Suppress("UNCHECKED_CAST")
- bind(T::class.java).annotatedWith(Names.named(it.name)).to(T::class.java.classLoader.loadClass(it.className) as Class<T>)
- }
-}
-
-private inline fun <reified Base : Any, reified T : Base> Binder.bindNameAnnotated(name: String) {
- bind(Base::class.java).annotatedWith(Names.named(name)).to(T::class.java)
-}
-
-
-inline fun <reified T: Any> Binder.bind(): AnnotatedBindingBuilder<T> = bind(T::class.java)
-
-inline fun <reified T: Any> Binder.lazyBind(): Lazy<AnnotatedBindingBuilder<T>> = lazy { bind(T::class.java) }
-
-inline infix fun <reified T: Any, TKClass: KClass<out T>> Lazy<AnnotatedBindingBuilder<T>>.toOptional(kClass: TKClass?) =
- kClass?.let { value toType it }
-
-inline infix fun <reified T: Any, TKClass: KClass<out T>> AnnotatedBindingBuilder<T>.toType(kClass: TKClass) = to(kClass.java)
diff --git a/core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt b/core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt
index 5a155dc1..b410915c 100644
--- a/core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt
+++ b/core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt
@@ -4,5 +4,5 @@ import org.jetbrains.dokka.DocumentationNode
import org.jetbrains.dokka.pages.PageNode
interface DocumentationToPageTransformer {
- fun transform (d: DocumentationNode): PageNode
+ fun transform (d: DocumentationNode<*>): PageNode
} \ No newline at end of file