diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/build.gradle | 4 | ||||
-rw-r--r-- | core/src/main/kotlin/DokkaBootstrapImpl.kt | 76 | ||||
-rw-r--r-- | core/src/main/kotlin/Formats/AnalysisComponents.kt | 45 | ||||
-rw-r--r-- | core/src/main/kotlin/Formats/FormatDescriptor.kt | 43 | ||||
-rw-r--r-- | core/src/main/kotlin/Generation/DokkaGenerator.kt | 214 | ||||
-rw-r--r-- | core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt | 344 | ||||
-rw-r--r-- | core/src/main/kotlin/Java/JavadocParser.kt | 402 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt | 188 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/DocumentationBuilder.kt | 534 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt | 33 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/KotlinLanguageService.kt | 473 | ||||
-rw-r--r-- | core/src/main/kotlin/Languages/CommonLanguageService.kt | 84 | ||||
-rw-r--r-- | core/src/main/kotlin/Languages/LanguageService.kt | 41 | ||||
-rw-r--r-- | core/src/main/kotlin/Model/PackageDocs.kt | 136 | ||||
-rw-r--r-- | core/src/main/kotlin/Utilities/DokkaModules.kt | 82 | ||||
-rw-r--r-- | core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt | 2 |
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("*/", "*/") - .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 |