aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.idea/compiler.xml10
-rw-r--r--.idea/kotlinc.xml4
-rw-r--r--core/build.gradle4
-rw-r--r--core/src/main/kotlin/DokkaBootstrapImpl.kt76
-rw-r--r--core/src/main/kotlin/Formats/AnalysisComponents.kt45
-rw-r--r--core/src/main/kotlin/Formats/FormatDescriptor.kt43
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt214
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt344
-rw-r--r--core/src/main/kotlin/Java/JavadocParser.kt402
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt188
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt534
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt33
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinLanguageService.kt473
-rw-r--r--core/src/main/kotlin/Languages/CommonLanguageService.kt84
-rw-r--r--core/src/main/kotlin/Languages/LanguageService.kt41
-rw-r--r--core/src/main/kotlin/Model/PackageDocs.kt136
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModules.kt82
-rw-r--r--core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt2
-rw-r--r--settings.gradle20
19 files changed, 25 insertions, 2710 deletions
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index d3328b68..111dac2e 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -34,8 +34,18 @@
<module name="dokka.buildSrc.test" target="1.8" />
<module name="dokka.core.main" target="1.8" />
<module name="dokka.core.test" target="1.8" />
+ <module name="dokka.core.testApi.main" target="1.8" />
+ <module name="dokka.core.testApi.test" target="1.8" />
+ <module name="dokka.coreDependencies.main" target="1.8" />
+ <module name="dokka.coreDependencies.test" target="1.8" />
+ <module name="dokka.integration-tests.gradle-integration-tests.main" target="1.8" />
+ <module name="dokka.integration-tests.gradle-integration-tests.test" target="1.8" />
<module name="dokka.integration.main" target="1.8" />
<module name="dokka.integration.test" target="1.8" />
+ <module name="dokka.plugins.javadoc8.main" target="1.8" />
+ <module name="dokka.plugins.javadoc8.test" target="1.8" />
+ <module name="dokka.plugins.main" target="1.8" />
+ <module name="dokka.plugins.test" target="1.8" />
<module name="dokka.runners.android-gradle-plugin.main" target="1.8" />
<module name="dokka.runners.android-gradle-plugin.test" target="1.8" />
<module name="dokka.runners.ant.main" target="1.8" />
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 38d23597..5a05248b 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -5,7 +5,7 @@
<option name="sourceMapPrefix" />
</component>
<component name="KotlinCommonCompilerArguments">
- <option name="apiVersion" value="1.1" />
- <option name="languageVersion" value="1.2" />
+ <option name="apiVersion" value="1.3" />
+ <option name="languageVersion" value="1.3" />
</component>
</project> \ No newline at end of file
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)
-